2016-05-11 3 views
2

я пытался сделать что-то вроде этого (это надуманный пример для демонстрационных целей):Инициализация констант класса в Swift

class Test { 
    let hello = "hello" 
    let world = "world" 
    let phrase: String { 
    return self.hello + self.world 
    } 
} 

, но вы не можете использовать let для вычисляемых свойств в Swift. Есть ли способ сделать это без необходимости писать метод init()? Благодаря!

ответ

4

Причина let не работает свойство только для чтения рассчитывается потому, что он используется утверждать, что фактическое значение свойства никогда не изменится после того, как будет установлено - не означает, что свойство доступно только для чтения. Как Apple docs сказать (курсив мой):

Вы должны объявить вычисляемые свойства - в то числе только для чтения вычислено свойства - как переменные свойства с вар ключевым словом, потому что их значение не зафиксировано. Ключевое слово let используется только для констант свойств, чтобы указать, что их значения не могут быть изменены, если они установлены как часть инициализации экземпляра.

поэтому Вам нужно использовать var для того, чтобы отразить тот факт, что значение вычисляемого свойства может измениться в любое время, как вы создаете его на лета, когда доступ к нему. Хотя в вашем коде это не может произойти - поскольку ваши hello и world свойствами являются let константы. Однако Swift не может это сделать, поэтому вам все равно придется использовать var.

Например:

class Test { 
    let hello = "hello" 
    let world = "world" 
    var phrase: String { 
     return self.hello + self.world 
    } 
} 

(Это не меняет читаемость собственности, - как потому, что вы не предоставили его сеттера, это все-таки только для чтения)

Однако в вашем случае вам может потребоваться вместо этого использовать lazy property, поскольку ваши свойства hello и world являются константами. Ложное свойство создается, когда оно впервые доступно, и сохраняет свою ценность на всю оставшуюся жизнь - это означает, что вам не придется продолжать конкатенировать две константы вместе каждый раз, когда вы обращаетесь к ней.

Например:

class Test { 
    let hello = "hello" 
    let world = "world" 
    lazy var phrase: String = { 
     return self.hello + self.world 
    }() 
} 

Другой характеристикой let свойств является то, что их значение всегда должно быть известно до инициализации. Поскольку значение ленивого свойства может быть неизвестно до этого, вам также необходимо определить его как var. Однако, как уже говорилось, это не определяет читаемость свойства - оно по-прежнему доступно только для чтения.


Если вы по-прежнему непреклонен желая let свойство для этого, то, насколько я понимаю, у вас есть два варианта.

Первый - самый аккуратный (хотя вы сказали, что не хотите этого делать) - вы можете назначить свое свойство phrase в инициализаторе. Пока вы делаете это до вызова super.init, вам не нужно иметь дело с опциями. Например:

class Test { 
    let hello = "hello" 
    let world = "world" 
    let phrase: String 

    init() { 
     phrase = hello+world 
    } 
} 

Вы просто не можете сделать это рядный, поскольку self в этой области видимости относится к статическому классу, не является экземпляром класса. Поэтому вы не можете получить доступ к членам экземпляра и использовать init() или ленивое/вычисленное свойство.

Второй вариант довольно Hacky - вы можете отразить ваши hello и world свойства на уровне класса, так что поэтому вы можете получить доступ к ним встроенный в вашей phrase декларации. Например:

class Test { 
    static let hello = "hello" 
    static let world = "world" 

    // for some reason, Swift has trouble inferring the type 
    // of the static mirrored versions of these properties 
    let hello:String = Test.hello 
    let world:String = Test.world 

    let phrase = hello+world 
} 

Если вы на самом деле не нужны ваши hello или world свойства как свойства экземпляра, то вы можете просто сделать их static - который решит вашу проблему.

+1

Жаль, что неизменяемость 'hello' и' world' (оба с использованием 'let') не применяются транзитно к фразе. По идее, вывод из неизменных свойств также должен быть неизменным. – Alexander

+0

@AMomchilov Правда, для компилятора наверняка было бы понятно, можно ли считать вычисленное свойство неизменным или нет - однако вы должны учитывать влияние на дизайн компилятора. Вам нужно будет выполнить поиск по всему телу вычисленного свойства, включая любые вызовы методов, любые другие расчетные свойства, чтобы выработать, если результат является неизменным. Конечный результат может быть довольно грязным и неинтуитивным - и, возможно, имеет больше случаев с краем, чем текущий синтаксис. – Hamish

+0

Я уверен, что компилятор будет делать это по 100 другим причинам оптимизации ниши. Я расскажу об этом в списке рассылки быстрой эволюции. – Alexander

2

Да, чтобы заставить его работать как вычисленные свойства, замените let на var. Мол,

class Test { 
    let hello = "hello" 
    let world = "world" 
    var phrase: String { 
    return self.hello + self.world 
    } 
} 

Таким образом, вы можете использовать его без инициализации()