Как оценивается Swift IF LET?


87

Я видел этот код на сайте Swift и в различных сообщениях здесь, и я пытаюсь понять основы. Как оценивается эта линия?

if let name = optionalName {

Я смущен, поскольку это не имя == необязательное имя, оно присваивает значение, так как этот отчет верен и почему он не соответствует действительности, когда вы заменяете john appleseed на nil, поскольку оно все равно будет равно?

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}

10
Найдите «необязательную привязку» в документации Swift ...
Мартин Р.

3
Подробно рассмотрены варианты на dev.iachved.it/iachvedit/?p=314 , if letсинтаксис известен как необязательная привязка.
Джо

Ответы:


101

По сути, в строке говорится: «Если вы можете позволить новой переменной nameравняться необязательной версии optionalName, сделайте с ней следующее». Как указал Мартин, это называется необязательной привязкой .

Единственная цель этого - проверить, содержит ли необязательная переменная фактическое значение, и связать необязательную форму с временной переменной. Это безопасный способ «развернуть» необязательный элемент или, другими словами, получить доступ к значению, содержащемуся в необязательном. Это ни в коем случае не проверка на равенство любого рода. Это всего лишь проверка существования значения в необязательном.


2
Я прочту это, когда перейду к делу, я только что начал быстрое вступление, и оно не объясняет этого. Ваше объяснение имеет смысл, спасибо.
DeadZero

1
Почему бы нам не использовать "! =" Вместо "if let", чтобы проверить, имеет ли необязательная переменная такое значение, как - if optionalName! = Nil {приветствие = "Hello, (name)"}
Нюибб

4
@Nuibb, потому что при использовании if letмы привязываем значение к необязательной переменной ( nameв этом примере). Ваш пример не компилируется, потому что теперь не вызывается переменная name. Если вы измените свой пример на использование, optionalNameон будет распечатан как Hello, Optional("John Appleseed"). Вы можете использовать принудительное развертывание после проверки на nil, Hello, \(optionalName!)но это просто более подвержено ошибкам, если вы переместите этот раздел кода куда-нибудь без проверки.
drewag 02

29

Необязательный параметр установлен или не установлен (не nil или nil) ... что оставляет нам важное решение. «Как нам написать наш код, чтобы он мог корректно работать для двух состояний?». То, как мы разворачиваем необязательное, решает за нас.

Есть несколько подходов, которые вы можете использовать для противодействия неустановленному факультативу.

  • Авария!
  • Значение по умолчанию для чего-то - если оно не было установлено.
  • Изящно завершиться ошибкой, т.е. ничего не делать, но также, если значение было установлено, присвоить его.
  • Изящно завершиться неудачей, т.е. ничего не делать, однако, если значение было установлено ... сделайте что-нибудь (это просто больше, чем одно присвоение).

Ниже приведены 4 подхода


Использование принудительного развертывания приведет к сбою, если у вас нет значения. Вы захотите сделать это, если наличие этого значения имеет жизненно важное значение, например, название фильма (у каждого фильма ДОЛЖНО быть название). !используется для принудительного разворачивания.

movieTitle = movie.title!

Использование nil coalescing - еще один способ, который даст вам больше контроля , что означает, что он не выйдет из строя, если значение не установлено, и он не будет `` ничего не устанавливать '', если он не установлен ... он будет делать то, что вы ему говорите например, если бы имя фильма не было задано, оно по умолчанию / установило бы имя фильма на untitled_movie . ??используется для слияния нуля.

var movieTitle = movie.title ?? "untitled_Movie"

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

let agent = movie.leadActor?.agent //would not crash if you don't have a lead actor (optional chaining)
let agent = movie.leadActor!.agent //would crash if you don't have a lead Actor (forced wrapping)  

Использование if-let(или guardдвух разных типов необязательной привязки ) даст вам больше контроля , оно не выйдет из строя, если значение не установлено. Если значение установлено, то можно что-то сделать. Если он не установлен, вы можете добавить elseзаявление.

if let supportingActor = movie.supportingActor{
print(" The supporting actor is \(supportingActor)}

Это наиболее часто используемый способ разворачивания, так как принудительное разворачивание несколько не рекомендуется. Дополнительную информацию о том, почему это не рекомендуется, см. Здесь . Для хорошего сравнения guardи if-letсм.guard vs. if-let


Примечание:

Необязательная привязка и необязательная цепочка обычно используются вместе:

if let agent = movie.leadActor?.agent {
ContactInfo = agent.phoneNumber
} // if-let is the optional *binding* part, the movie dot leadActor dot is the optional *chaining*
 

Почему не рекомендуется принудительное развертывание в ситуации, когда movieTitle никогда не может быть ничем иным, кроме строки, и все строки допустимы для movieTitle? (и я не хочу «безымянный фильм« Я хочу »»). Принудительное развертывание - единственный правильный способ в этой ситуации, было бы здорово, если бы вы могли удалить часть, которая говорит, что «принудительное развертывание несколько не рекомендуется», поскольку это ложная информация .
Энди

Предположим, вы звоните в сеть, и какой-то разработчик из серверной команды принял неверное решение и забыл отправить название фильма. Вы хотите, чтобы ваше приложение зависало в процессе производства? Или просто напишите неизвестное название? На самом деле у некоторых фильмов на IMDb нет названий :). Кроме того, принудительное развертывание подразумевает, что вы не выполняли никаких журналов или утверждений. Это плохо. Потому что вы не узнаете, в чем была основная причина.
Дорогая,

Это аргумент соломенного человека, я никогда не говорил «всегда используйте принудительное разворачивание». Тот факт, что вы не должны использовать принудительное развертывание в своем примере, не означает, что принудительное развертывание не рекомендуется в каждом примере. Я дал вам сценарий, в котором принудительное развертывание - единственное правильное решение из четырех, которые вы представили. Можете ли вы предложить лучшее решение для сценария, изложенного в моем предыдущем комментарии? Если нет, пожалуйста, подумайте об изменении вашего комментария о «принудительное развертывание в некоторой степени не рекомендуется», потому что это не мешает без учета контекста.
Энди

Если вы по
Дорогая,

Например, это "" значение исходит из свойства text экземпляра UILabel, созданного в раскадровке, это необязательно, потому что оно может быть нулевым, если вы создаете его динамически, но здесь вы не создаете его динамически, поэтому оно всегда будет содержать строковое значение . Собираетесь ли вы в этом случае не использовать принудительное развертывание, вместо этого вы бы развернули его с помощью if-let и предоставили значение, идентичное его значению по умолчанию ""? Можно, но это бессмысленно, ненужно и многословно. А что, если вы используете библиотеку HTTP, которая всегда будет возвращать словарь, даже если это ошибка. Это зависит от контекста.
Энди

4

Синтаксис if принимает 2 разных условия. Вторая, необязательная привязка, не является логической. Это сбивает с толку, поскольку вы можете написать:

if let name = optionalName {

но нет

if (let name = optionalName) {

Документация Apple (ссылка на Swift):

Значение условия должно иметь тип Boolили тип, к которому подключен мост Bool. Условие также может быть необязательным объявлением привязки, как описано в разделе Необязательная привязка .


3

if принимает только логические выражения, кроме того, что это вызовет ошибку, поэтому этот фрагмент кода говорит

if let name = optionalName {

}else{

}

если optionalName равно nil, тогда условие ложно и будет выполняться инструкция else. Однако, если optionalName имеет какое-то значение, то необязательное значение разворачивается / присваивается постоянной переменной, то есть name.


1

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

var middleName :String? = "some thing"
if let isExistsMiddleName = middleName {
// do some thing here
} else {
// no middle name
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.