Что такое" развернутое значение " в Swift?

Я изучаю Swift для iOS 8 / OSX 10.10, следуя в этом уроке, и термин "развернул стоимостью " используется несколько раз, как в этом абзаце (под объекты и класс):

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

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare?.sideLength

Я не понимаю, и искал в интернете без везения.

что это значит?


редактировать

из ответа Цезаря есть небольшая разница между выводом исходного кода и окончательным решение (протестировано на игровой площадке):

исходный код

Original code

Цезарий это

Cezary's solution

свойства суперкласса отображаются на выходе во втором случае, в то время как в первом случае есть пустой объект.

разве результат не должен быть одинаковым в обоих случаях?

В Ответ : что такое необязательное значение в Swift?

4 ответов


во-первых, вы должны понять, что такое необязательный тип. Необязательный тип в основном означает, что переменная может быть nil.

пример:

var canBeNil : Int? = 4
canBeNil = nil

знак вопроса указывает на то, что canBeNil может быть nil.

это не сработает:

var cantBeNil : Int = 4
cantBeNil = nil // can't do this

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

var canBeNil : Int? = 4
println(canBeNil!)

ваш код должен выглядеть так:

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare!.sideLength

sidenote:

вы также можете объявить optionals для автоматического разворачивания, используя восклицательный знак вместо вопросительного знака.

пример:

var canBeNil : Int! = 4
print(canBeNil) // no unwrapping needed

альтернативный способ исправить ваш код:

let optionalSquare: Square! = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare.sideLength

EDIT:

разница, которую вы видите, является именно симптомом того, что необязательное значение завернут. Поверх него еще один слой. The развернул версия просто показывает прямой объект, потому что он, ну, развернут.

быстрое сравнение игровой площадки:

playground

в первом и втором случаях объект не разворачивается автоматически, поэтому вы видите два "слоя" ({{...}}), тогда как в третьем случае, вы видите только один слой ({...}), поскольку объект автоматически развернул.

разница между первым случаем и вторыми двумя случаями заключается в том, что вторые два случая дадут вам ошибку времени выполнения, если optionalSquare установлено значение nil. Используя синтаксис в первом случае, вы можете сделать что-то вроде этого:

if let sideLength = optionalSquare?.sideLength {
    println("sideLength is not nil")
} else {
    println("sidelength is nil")
}

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

Итак, позвольте мне помочь этим коллегам "правополушарным" (визуальное мышление) разработчикам, предоставив другую перспективу в дополнение к правильному ответу. Вот хорошая аналогия, которая мне очень помогла.

Подарок На День Рождения Упаковка Аналогия

думайте о optionals как быть как подарки на день рождения, которые приходят в жесткой, жесткой, цветной упаковке.

вы не знаете, есть ли что - нибудь внутри упаковки, пока вы не развернете настоящее-может быть, нет ничего вообще внутри! Если внутри что-то есть, это может быть еще один подарок, который также завернут, и который также может не содержать ничего. Вы даже можете развернуть 100 вложенных подарков, чтобы наконец обнаружить, что есть ничего, кроме оберточной.

если значение необязательно не nil, теперь вы показали коробку, содержащую что-то. Но, особенно если значение явно не типизировано и является переменной, а не предопределенной константой, вам все равно может потребоваться открыть окно прежде чем вы сможете узнать что-нибудь конкретное о том, что находится в коробке, например что-то типа это, или что фактический стоимостью есть.

что в коробке?! Аналогия

даже после того, как вы разворачиваете переменную, вы все еще похожи на Брэда Питта в последняя сцена в SE7EN (предупреждение: спойлеры и очень R-рейтинг нецензурной брани и насилия), потому что даже после того, как вы развернули настоящее, вы находитесь в следующей ситуации:теперь у вас есть nil, или коробка, содержащая что-то (но вы не знаете что).

вы можете знать тип что-то. Например, если вы объявили переменную как тип, [Int:Any?], тогда вы знали бы, что у вас есть (потенциально пустой) словарь с целочисленными индексами, которые дают обернутое содержимое любого старого типа.

вот почему работа с типами коллекций (словари и массивы) в Swift может стать своего рода волосатым.

пример:

typealias presentType = [Int:Any?]

func wrap(i:Int, gift:Any?) -> presentType? {
    if(i != 0) {
        let box : presentType = [i:wrap(i-1,gift:gift)]
        return box
    }
    else {
        let box = [i:gift]
        return box
    }
}

func getGift() -> String? {
    return "foobar"
}

let f00 = wrap(10,gift:getGift())

//Now we have to unwrap f00, unwrap its entry, then force cast it into the type we hope it is, and then repeat this in nested fashion until we get to the final value.

var b4r = (((((((((((f00![10]! as! [Int:Any?])[9]! as! [Int:Any?])[8]! as! [Int:Any?])[7]! as! [Int:Any?])[6]! as! [Int:Any?])[5]! as! [Int:Any?])[4]! as! [Int:Any?])[3]! as! [Int:Any?])[2]! as! [Int:Any?])[1]! as! [Int:Any?])[0])

//Now we have to DOUBLE UNWRAP the final value (because, remember, getGift returns an optional) AND force cast it to the type we hope it is

let asdf : String = b4r!! as! String

print(asdf)

Свифт устанавливает высокую награду на типе безопасности. Весь язык Swift был разработан с учетом безопасности. Это один из признаков Swift и тот, который вы должны приветствовать с распростертыми объятиями. Это поможет в разработке чистого, читаемого кода и поможет сохранить ваше приложение от сбоя.

все optionals в Swift разграничены с ? символ. Установив ? после имени типа, в котором вы объявляете как необязательный, вы по существу литье это не как тип, в котором перед ?, а как дополнительно тип.


Примечание: переменная или тип Int и не аналогично Int?. Они представляют собой два разных типа, которые не могут работать друг на друга.


Используя Дополнительно

var myString: String?

myString = "foobar"

это не означает, что вы работаете с типом String. Это означает, что вы работаете с типа String? (строка необязательная или необязательная строка). На самом деле, всякий раз, когда вы пытаетесь

print(myString)

во время выполнения, консоль отладки будет печататься Optional("foobar"). В "Optional()" часть указывает, что эта переменная может иметь или не иметь значения во время выполнения, но в настоящее время она содержит строку "foobar". Это"Optional()" индикация останется если вы не сделаете что вызвано "разворачивать" опционное значение.

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


Условно Разворачивание проверит, является ли значение в необязательном nil или нет. Если это нет nil, будет вновь созданная постоянная переменная, которой будет присвоено значение и развернул в необязательную константу. И оттуда вы можете безопасно использовать необязательный в if блок.

Примечание: Вы можете дать условно развернутой константе то же имя, что и необязательная переменная, которую вы разворачиваете.

if let myString = myString {
    print(myString)
    // will print "foobar"
}

условно разворачивать optionals самый чистый путь достигнуть необязательное значение, потому что если оно содержит значение nil, то все в блоке if let не будет выполняться. Конечно, как и любой оператор if, вы можете включить блок else

if let myString = myString {
    print(myString)
    // will print "foobar"
}
else {
    print("No value")
}

Насильно Разворачивая делается с использованием того, что известно как ! ("bang") оператор. Это менее безопасно, но все же позволяет компилировать ваш код. Однако всякий раз, когда вы используете оператор bang, вы должны быть на 1000% уверены, что ваша переменная действительно содержит твердое тело значение перед принудительно разворачивать.

var myString: String?

myString = "foobar"

print(myString!)

это выше полностью действительный код Swift. Он печатает значение myString это было установлено как "foobar". Пользователь увидит foobar напечатано в консоли, и это все. Но предположим, что значение никогда не было установлено:

var myString: String?

print(myString!) 

теперь у нас другая ситуация на наших руках. В отличие от Objective-C, всякий раз, когда делается попытка принудительно развернуть необязательный, а необязательный не установлен и является nil, когда вы пытаетесь развернуть необязательный, чтобы увидеть, что внутри вашего приложения произойдет сбой.


разворачивание с литьем типа. Как мы уже говорили ранее, пока вы unwrapping необязательный вы на самом деле литье в необязательный тип, вы также можете привести необязательный к другому типу. Например:

var something: Any?

где-то в коде переменной something будет установлен с некоторым значением. Может быть, мы используем дженерики или, может быть, есть какие-то другие логика, которая происходит, заставит это измениться. Поэтому позже в нашем коде мы хотим использовать something но все же можно относиться к нему по-другому, если это другой тип. В этом случае вы захотите использовать as ключевое слово, чтобы определить это:

Примечание:as оператор-это то, как вы вводите приведение в Swift.

// Conditionally
if let thing = something as? Int {
    print(thing) // 0
}

// Optionally
let thing = something as? Int
print(thing) // Optional(0)

// Forcibly
let thing = something as! Int
print(thing) // 0, if no exception is raised

обратите внимание на разницу между двумя as ключевые слова. Как и раньше, когда мы насильно развернули необязательный, мы использовали ! оператор взрыва, чтобы сделать это. Здесь вы сделаете то же самое, но вместо того, чтобы бросать как просто необязательный, вы бросаете его также как Int. И это должны уметь быть подавленным как Int, иначе, как с помощью оператора взрыва, когда значение nil ваше приложение рухнет.

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

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

тем не менее кастинг с as! позволит ваш код для компиляции. По кастингу с as? - это другая история. На самом деле,as? объявляет свой Int как совершенно другой тип данных все вместе.

теперь Optional(0)

и если вы когда-нибудь пытались сделать домашнее задание, написав что-то вроде

1 + Optional(1) = 2

ваш учитель математики, вероятно, дал бы вам"F". То же самое со Свифтом. Кроме того, Swift предпочел бы вообще не компилировать, а не давать вам оценку. потому что в конце дня необязательный может быть фактически равен нулю.

Безопасность Детей.


'?'означает необязательное цепное выражение

the'!'средство есть сила-значение
enter image description here