Jak oceniany jest Swift IF LET?

90

Widziałem ten kod w witrynie Swift i różnych postach tutaj i próbuję uchwycić podstawy. Jak oceniana jest ta linia?

if let name = optionalName {

Jestem zdezorientowany, ponieważ to nie jest nazwa == opcjonalna nazwa, przypisuje wartość, więc w jaki sposób to zgłasza prawdę i dlaczego nie jest prawdą, gdy zamieniasz na nil z John Appleeed, skoro nadal będzie równy?

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}
DeadZero
źródło
10
Wyszukaj "opcjonalne powiązanie" w dokumentacji Swift ...
Martin R
3
Szczegółowe omówienie opcji na dev.iachieved.it/iachievedit/?p=314 , if letskładnia jest znana jako opcjonalne wiązanie.
Joe,

Odpowiedzi:

105

Zasadniczo wiersz mówi: „jeśli możesz pozwolić nowej zmiennej namerównać się nieopcjonalnej wersji optionalName, wykonaj z nią następujące czynności”. Jak zauważył Martin, nazywa się to opcjonalnym wiązaniem .

Jego jedynym celem jest sprawdzenie, czy zmienna opcjonalna zawiera rzeczywistą wartość i powiązanie formy nieopcjonalnej ze zmienną tymczasową. Jest to bezpieczny sposób „rozpakowania” elementu opcjonalnego lub innymi słowy, uzyskania dostępu do wartości zawartej w opcjonalnym. W żaden sposób nie jest to próba jakiejkolwiek równości. To tylko testowanie istnienia wartości w opcjonalnym.

drewag
źródło
2
Przeczytam to, kiedy się do tego zabiorę, jestem dopiero na początku szybkiego intro i nie wyjaśnia tego. Twoje wyjaśnienie ma sens, dzięki.
DeadZero
1
Dlaczego nie mielibyśmy użyć „! =” Zamiast „if let”, aby sprawdzić, czy opcjonalna zmienna ma wartość taką jak - if optionalName! = Nil {pozdrowienia = "Hello, (name)"}
Nuibb
4
@Nuibb, ponieważ podczas używania wiążemy if letwartość ze zmienną nieobowiązkową ( namew tym przykładzie). Twój przykład nie skompilowałby się, ponieważ teraz nie ma wywoływanej zmiennej name. Jeśli zmienisz przykład, aby optionalNamego używać , zostanie wydrukowany jako Hello, Optional("John Appleseed"). Możesz użyć wymuszonego rozpakowywania po sprawdzeniu wartości nil, Hello, \(optionalName!)ale jest to po prostu bardziej podatne na błędy, jeśli przeniesiesz tę sekcję kodu gdzieś bez sprawdzania.
drewag
30

Opcjonalny jest ustawiony lub nieustawiony (nie zerowy lub nie) ... pozostawiając nam ważną decyzję. „Jak napisać nasz kod, aby działał poprawnie w dwóch stanach?”. Decyduje o tym sposób, w jaki rozpakujemy opcjonalne.

Istnieje kilka podejść, których można użyć, aby przeciwdziałać nie ustawionemu opcjonalnemu.

  • Wypadek!
  • Domyślnie wartość na coś - jeśli nie została ustawiona.
  • Wdzięcznie zawieść, tj. Nic nie rób, ale także jeśli wartość została ustawiona, przypisz ją.
  • Z wdziękiem niepowodzenie, tj. Nic nie rób, ale jeśli wartość została ustawiona ... zrób coś (to po prostu więcej niż jedno przypisanie).

Poniżej znajdują się 4 podejścia


Używanie wymuszonego rozpakowywania spowoduje awarię, jeśli nie masz wartości. Chciałbyś to zrobić, jeśli posiadanie tej wartości ma kluczowe znaczenie, np. Tytuł filmu (każdy film MUSI mieć nazwę). !służy do wymuszonego rozpakowywania.

movieTitle = movie.title!

Użycie koalescencji zerowej to kolejny sposób, który da ci większą kontrolę , co oznacza, że ​​nie ulegnie awarii, jeśli wartość nie zostanie ustawiona, ani nie `` nic nie ustawi '', jeśli nie jest ustawiona ... zrobi to, co powiesz by to zrobić, np. domyślnie / ustawiłoby nazwę filmu na untitled_movie, gdyby nie ustawiono nazwy. ??służy do koalescencji zerowej.

var movieTitle = movie.title ?? "untitled_Movie"

Używanie opcjonalnego łączenia łańcuchowego nic nie da, jeśli nie masz wartości, i ustawi wartość, jeśli masz wartość. Robisz to dla czegoś, dla czego ustalenie wartości nie jest istotne, np. Dla nazwiska agenta twojego aktora . ?służy do opcjonalnego łączenia w łańcuch.

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)  

Użycie if-let(lub guardktóre są dwoma różnymi typami opcjonalnego wiązania ) zapewni większą kontrolę , nie ulegnie awarii, jeśli wartość nie zostanie ustawiona. Jeśli wartość jest ustawiona, możesz coś zrobić. Jeśli nie jest ustawiona, możesz dodać elseinstrukcję.

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

Jest to najczęściej stosowany sposób rozpakowywania, ponieważ wymuszone rozpakowywanie jest nieco odradzane. Więcej dyskusji na temat tego, dlaczego odradza się, można znaleźć tutaj . Aby uzyskać dobre porównanie między guardi if-letzobaczguard vs. if-let


Dygresja:

Opcjonalne wiązanie i opcjonalne łączenie łańcuchowe są powszechnie używane razem:

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*
 
kochanie
źródło
Dlaczego wymuszone rozpakowywanie miałoby być zniechęcane, biorąc pod uwagę sytuację, w której movieTitle nigdy nie może być niczym innym niż ciągiem, a wszystkie ciągi są prawidłowe dla movieTitle? (i nie chcę „filmu bez tytułu” Chcę ”) Wymuszone rozpakowanie jest jedynym właściwym sposobem w tej sytuacji. Byłoby wspaniale, gdybyś mógł usunąć część z napisem„ wymuszone rozpakowywanie jest nieco odradzane ”, ponieważ to nieprawda .
Andy
Załóżmy, że wykonujesz połączenie sieciowe, a jakiś programista z zespołu serwerów podjął złą decyzję i zapomniał wysłać tytuł filmu. Czy chcesz, aby Twoja aplikacja ulegała awarii podczas produkcji? A może po prostu napisz nieznany tytuł? Właściwie niektóre filmy na IMDb nie mają tytułów :). Dodatkowo wymuszenie rozpakowania oznacza, że ​​nie wykonałeś żadnego logowania ani potwierdzeń. To źle. Ponieważ nie wiesz, jaka była pierwotna przyczyna.
Miód
To słomkowy argument, nigdy nie powiedziałem: „zawsze używaj wymuszonego rozpakowywania”. To, że nie powinieneś używać wymuszonego rozpakowywania w swoim przykładzie, nie oznacza, że ​​wymuszone rozpakowywanie jest odradzane w każdym przykładzie. Podałem ci scenariusz, w którym wymuszone rozpakowanie jest jedynym słusznym rozwiązaniem spośród czterech, które przedstawiłeś. Czy możesz podać lepsze rozwiązanie scenariusza przedstawionego w moim poprzednim komentarzu? Jeśli nie, rozważ zmianę komentarza o „wymuszonym rozpakowywaniu jest nieco odradzane”, ponieważ nie jest to trochę odradzane bez uwzględnienia kontekstu.
Andy
Jeśli domyślnie ustawisz coś na „”, to nie jest już opcjonalne
Honey
Na przykład wartość „” pochodzi z właściwości text instancji UILabel utworzonej w scenorysie, jest opcjonalna, ponieważ może wynosić zero, jeśli utworzysz ją dynamicznie, ale tutaj nie tworzysz jej dynamicznie, więc zawsze będzie zawierała wartość ciągu . Czy nie zamierzasz używać wymuszonego rozpakowywania w tym przypadku, zamiast tego rozpakujesz za pomocą if-let i podasz wartość, która jest identyczna z wartością domyślną „”? Możesz, ale to bezcelowe, niepotrzebne i rozwlekłe. A co, jeśli używasz biblioteki HTTP, która zawsze zwraca słownik, nawet jeśli jest to błąd. To zależy od kontekstu.
Andy
4

Składnia if akceptuje 2 różne warunki. Drugie, opcjonalne wiązanie, nie jest wartością logiczną. To jest mylące, jak możesz napisać:

if let name = optionalName {

ale nie

if (let name = optionalName) {

Dokumentacja Apple (odniesienie do Swift):

Wartość warunku musi być typu Boollub typem, do którego jest mostkowany Bool. Choroba ta może być również opcjonalnie deklaracja wiążące, jak to omówiono w Opcjonalnie Binding .

Pierre Marty
źródło
3

if przyjmuje tylko wyrażenia boolowskie, poza tym, że zwróciłby błąd, więc ten fragment kodu mówi

if let name = optionalName {

}else{

}

jeśli opcjonalna nazwa ma wartość nil, to warunek jest fałszywy i instrukcja w przeciwnym razie zostanie wykonana. Jednakże, jeśli optionalName ma jakąś wartość, to opcjonalna wartość jest rozpakowywana / przypisywana do stałej zmiennej, tj. Nazwa.

Anurag Bhakuni
źródło
1

Ilekroć pracujesz ze słabymi odwołaniami, opcjonalnymi typami lepiej byłoby użyć jeśli pozwolą chronić twój kod i uniknąć awarii Oto przykłady

var middleName :String? = "some thing"
if let isExistsMiddleName = middleName {
// do some thing here
} else {
// no middle name
}
Narendra G
źródło