Як оцінюється Swift IF LET?


87

Я бачив цей код на сайті Swift та різні публікації тут, і я намагаюся зрозуміти основи. Як оцінюється цей рядок?

if let name = optionalName {

Мене бентежить, оскільки це не name == необов’язкове ім’я, воно присвоює значення, так як же це звітність істинно і чому це не так, коли ви замінюєте John Johnseede на nil, оскільки воно все одно буде рівним?

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

10
Шукати "необов’язкове прив’язування" в документації Swift ...
Martin R

3
Детально розглянувши варіанти на dev.iachieved.it/iachievedit/?p=314 , if letсинтаксис відомий як необов’язкове прив’язування.
Джо

Відповіді:


101

По суті, у рядку сказано: "якщо ви можете дозволити новій змінній nameдорівнювати необов'язковій версії optionalName, зробіть з нею наступне". Як зазначав Мартін, це називається необов’язковим прив’язуванням .

Єдина мета - перевірити, чи містить необов’язкова змінна фактичне значення, та прив’язати необов’язкову форму до тимчасової змінної. Це безпечний спосіб «розгорнути» необов’язковий або іншими словами, отримати доступ до значення, що міститься в необов’язковому. Це жодним чином не перевірка рівності будь-якого виду. Це лише перевірка на наявність значення в необов’язковому.


2
Я прочитаю про це, коли я перейду до цього, я просто на початку швидкого вступу, і це не пояснює. Ви пояснюєте цілком логічно, дякую.
DeadZero

1
Чому б нам не використовувати "! =" Замість "if let", щоб перевірити, чи має необов'язкова змінна значення типу - if optionalName! = Nil {привітання = "Привіт, (ім'я)"}
Nuibb

4
@Nuibb, оскільки при використанні if letми прив'язуємо значення до необов'язкової змінної ( nameу цьому прикладі). Ваш приклад не компілюється, тому що зараз немає змінної, що викликається name. Якщо ви змінили свій приклад для використання, optionalNameвін роздрукується як Hello, Optional("John Appleseed"). Ви можете використовувати примусове розгортання після перевірки на нуль, Hello, \(optionalName!)але це просто більше схильне до помилок, якщо ви перемістите цей розділ коду кудись без перевірки.
drewag

29

Необов’язковим є або встановлений, або не встановлений (не нульовий або нульовий) ... залишаючи перед нами важливе рішення. "Як нам писати наш код, щоб він міг працювати коректно для обох станів?". Спосіб розгортання необов’язкового - це те, що вирішує нас.

Існує кілька підходів, якими можна протистояти невстановленому необов’язковому.

  • Крах!
  • Значення за замовчуванням для чогось - якщо воно не встановлене.
  • Витончено не вдається, тобто нічого не робити, але також якщо значення було встановлено, то присвойте його.
  • Витончено не вдається, тобто нічого не робити, проте якщо значення було встановлено ... зробіть щось (це просто більше, ніж одне призначення).

Нижче наведено 4 підходи


Використання примусового розгортання призведе до збою, якщо у вас немає значення. Ви хотіли б зробити це, якщо наявність цієї цінності є життєво важливим, наприклад, назва фільму (кожен фільм ПОВИНЕН мати назву). !використовується для примусового розгортання.

movieTitle = movie.title!

Використання коагуляції nil - це ще один спосіб, який надасть вам більше контролю , тобто він не збій, якщо значення не встановлено, і не буде "нічого не встановлювати", якщо його не встановити ... він буде робити те, що ви йому скажете це зробити, наприклад, за замовчуванням / встановить назву фільму на untitled_movie, якщо не буде встановлено ім'я. ??використовується для злиття нулів.

var movieTitle = movie.title ?? "untitled_Movie"

Використання необов’язкового Chaining нічого не дасть, якщо у вас немає значення, і встановить значення, якщо у вас є значення. Ви робите це для того, що встановлення його значення не має життєво важливого значення, наприклад, для імені агента вашого актора . ?використовується для додаткового ланцюжка.

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 не мають назв :). Крім того, примусове розгортання означає, що ви не робили жодних журналів чи тверджень. Це погано. Тому що ви не будете знати, що було першопричиною.
Мед

Це аргумент солом’яної людини, я ніколи не говорив, що «завжди застосовуй примусове розгортання». Те, що ви не повинні використовувати примусове розгортання у вашому прикладі, не означає, що примусове розгортання не рекомендується в кожному прикладі. Я дав вам сценарій, коли примусове розгортання є єдиним правильним рішенням із чотирьох представлених вами. Чи можете ви надати краще рішення сценарію, викладеному в моєму попередньому коментарі? Якщо ні, будь ласка, змініть свій коментар щодо "примусового розгортання дещо не рекомендується", оскільки це не дещо знеохочується без урахування контексту.
Енді

Якщо ви дефолтуєте щось за замовчуванням, тоді це вже не є необов’язковим
Мед,

Наприклад, "" значення походить від властивості тексту екземпляра UILabel, створеного в раскадровці, це необов'язково, оскільки воно може бути нульовим, якщо ви створюєте його динамічно, але тут ви не створюєте його динамічно, тому воно завжди буде містити значення рядка . Ви не збираєтесь використовувати примусове розгортання в цьому випадку, натомість ви розгортаєтесь if-let і надаєте значення, яке ідентичне значенню за замовчуванням ""? Можна, але це безглуздо, непотрібно і багатослівно. А що, якщо ви використовуєте бібліотеку HTTP, яка завжди повертає словник, навіть якщо це помилка. Це залежить від контексту.
Енді,

4

Синтаксис if приймає 2 різні умови. Друге, необов’язкове прив’язування, не є логічним значенням. Це бентежить, як ви можете написати:

if let name = optionalName {

але не

if (let name = optionalName) {

Документація Apple (довідка Swift):

Значення умови повинно мати тип Boolабо тип, який пов’язаний з ним Bool. Умова також може бути необов'язковим зв'язуванням заяви, як описано в необов'язково Binding .


3

if приймає лише булеві вирази, крім того, що це призведе до помилки, тому цей фрагмент коду говорить

if let name = optionalName {

}else{

}

якщо опція optionalName дорівнює нулю, то умова хибна, і в іншому випадку буде виконано оператор. Однак, якщо optionalName має якесь значення, тоді необов'язкове значення розгортається / присвоюється постійній змінній, тобто імені.


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.