Почему я могу определить статическую константу, которая зависит от другой статической константы того же типа, но не от свойств? - PullRequest
1 голос
/ 31 октября 2019

Мне знакомо получение ошибки при попытке доступа к self до инициализации всех свойств. Одна вещь, которую я никогда не понимал, - это то, почему я могу инициализировать static константы с зависимостями от других static свойств в том же type без каких-либо ошибок.

В чем причина такого поведения? Почему определение static констант не дает мне ошибки времени компиляции, а константы свойств это делают?

Некоторый код:

struct MyStruct {
    static let myStatic = 1
    // No error on this line...
    static let myStaticPlusOne = myStatic + 1

    let myInstance = 1
    // ... But a compile time error on this one! What makes the difference?
    let myInstancePlusOne = myInstance + 1
}

Там имеет , чтобы бытьвремя, когда эта структура загружается в память или что-то еще, загружая статические переменные. Я вижу это время точно так же, как и время создания нового экземпляра type. Я не могу ясно увидеть разницу между этими двумя. У обоих есть время, когда одно свойство инициализируется, а другое нет. Чем я могу получить доступ к своей статической переменной из другой статической переменной?

Ответы [ 2 ]

3 голосов
/ 31 октября 2019

Тип и экземпляр.

  • Тип MyStruct всегда существует. static свойства принадлежат типу. Поэтому они просто сидят там и могут делать все, что им нравится или быть связаны каким-либо образом. Ладно, да, она должна появиться при запуске программы, но под капотом все инициализаторы статических свойств lazy, так что вполне нормально, чтобы один зависел от другого (конечно, не по кругу).

  • Экземпляр MyStruct - это вещь, которую нужно создавать каждый раз, когда вы говорите MyStruct(...). Когда вы говорите это, свойства экземпляра должны быть инициализированы. Свойство экземпляра (не static) принадлежит экземпляру. Таким образом, значение его инициализатора не может ссылаться на self, потому что self - это именно то, что мы находимся в процессе создания, то есть экземпляр. Эта строка:

    let myInstancePlusOne = myInstance + 1
    

    ... действительно означает

    let myInstancePlusOne = self.myInstance + 1
    

    ... но это именно то, что вы не можете сказать;на момент инициализации этого свойства self еще нет, это то, что вы инициализируете. И вы можете обойти это, объявив это свойство lazy (с другими настройками в синтаксисе).

1 голос
/ 01 ноября 2019

Это из-за следующих двух причин:

  • Каждое глобальное свойство лениво относится к компьютеру. Не интуитивно понятно, что их не нужно отмечать lazy.

  • Круговая зависимость не допускается


Более простой пример того, что сказал Мэтт:

class X {
    static var a = 10
    static var b = 20
}

class Y {
    static var a = 10 * Y.b
    static var b = 20
}

class Z {
    static var a = 10 * Z.b
    static var b = 20 * Z.a // ERROR: Type 'Z' has no member 'a' 
}

класс Z недопустим, потому что у вас круговая зависимость. Но я не думаю, что ошибка не ясна.

Это означает, что компилятор попытается выяснить зависимости и начнет строить тип из значения, которое ни от чего не зависит, затем перейдет к построениюдругие свойства типа. Но если он не может этого сделать, он выдаст ошибку!

Как вы упомянули в комментариях. docs говорят:

Глобальные константы и переменные всегда вычисляются лениво, аналогично Lazy Stored Properties. В отличие от ленивых хранимых свойств, глобальные константы и переменные не должны быть отмечены модификатором lazy.

Локальные константы и переменные никогда не вычисляются лениво.


Следующее будетпропустите компилятор, но он потерпит крах при доступе к свойству

class C {
    lazy var a : Int = {
        let _a = self.b + 30
        return _a
    }()

    lazy var b : Int = {
        let _b = self.a + 20
        return _b
    }()
}

let d = C().a // ERROR!

Так что, как вы можете видеть для обоих, вам нужно создать экземпляр / тип на основе сохраненного значения, а затем вычислить другие свойства из этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...