Szybkie oświadczenie if let w Kotlinie

123

Czy w Kotlinie jest odpowiednik kodu Swift poniżej?

if let a = b.val {

}
else {

}
iori24
źródło

Odpowiedzi:

255

Możesz użyć lettej funkcji w następujący sposób:

val a = b?.let {
    // If b is not null.
} ?: run {
    // If b is null.
}

Pamiętaj, że musisz wywołać tę runfunkcję tylko wtedy, gdy potrzebujesz bloku kodu. Możesz usunąć run-block, jeśli masz tylko oneliner po elvis-operator ( ?:).

Należy pamiętać, że runblok zostanie oceniony, jeśli bma wartość null lub jeśli wartość let-block wynosi null.

Z tego powodu zwykle potrzebujesz tylko ifwyrażenia.

val a = if (b == null) {
    // ...
} else {
    // ...
}

W takim przypadku else-block zostanie oszacowany tylko wtedy, gdy bnie jest null.

marstran
źródło
41
To nie jest równoważne. anie można uzyskać dostępu do środka leti runzablokować.
Jacky Choi
6
anie jest jeszcze zdefiniowana w zakresie leti run. Ale możesz uzyskać dostęp do wartości bwewnątrz za letpomocą niejawnego parametru it. To chyba służy temu samemu celowi.
marstran
1
Szybki kod kończy przypisanie aprzed tymi blokami kodu. I amożna dostać się do środka.
Jacky Choi
1
Do czego to przypisuje a? Jeśli tak b, to itsłuży dokładnie temu samemu celowi. Czy ponownie przypisuje az wynikiem val-block?
marstran
3
Możesz wejść tylko itz letbloku. Wynik bloku letlub runzostanie przypisany do a. Wynikiem jest ostatnie wyrażenie w bloku. Używasz zadania po zakończeniu let / porun zakończeniu, tak jak w przypadku każdego innego normalnego zadania.
marstran
51

Najpierw upewnijmy się, że rozumiemy semantykę podanego idiomu Swift:

if let a = <expr> {
     // then-block
}
else {
     // else-block
}

Oznacza to: „jeśli <expr> wynik ma wartość thenróżną od zera, wprowadź -block z symbolem apowiązanym z nieopakowaną wartością. W przeciwnym razie wprowadźelse blok.

Zwróć szczególną uwagę, że ajest to związane tylko do then-bloku . W Kotlinie możesz to łatwo uzyskać dzwoniąc

<expr>?.also { a ->
    // then-block
}

i możesz dodać plik else -block w ten sposób:

<expr>?.also { a ->
    // then-block
} ?: run {
    // else-block
}

Powoduje to taką samą semantykę, jak w idiomie Swift.

Marko Topolnik
źródło
11

Moja odpowiedź jest całkowicie kopiowana przez innych. Jednak nie mogę łatwo zrozumieć ich wypowiedzi. Więc myślę, że byłoby miło udzielić bardziej zrozumiałej odpowiedzi.

Szybko:

if let a = b.val {
  //use "a" as unwrapped
}
else {

}

W Kotlinie:

b.val?.let{a -> 
  //use "a" as unwrapped
} ?: run{
  //else case
}
Wu Yuan Chun
źródło
Użycie letzamiast alsooznacza, że runblok zostanie wykonany za każdym razem, gdy letblok zwróci null, co nie jest tym, czego chcemy.
Marko Topolnik
6

W przeciwieństwie do Swifta, nie trzeba rozpakowywać opcjonalnego przed użyciem go w Kotlinie. Moglibyśmy po prostu sprawdzić, czy wartość jest różna od null, a kompilator śledzi informacje o wykonanym sprawdzeniu i zezwala na użycie go jako rozpakowanego.

W Swift:

if let a = b.val {
  //use "a" as unwrapped
} else {

}

W Kotlinie:

if b.val != null {
  //use "b.val" as unwrapped
} else {

}

Więcej takich przypadków użycia można znaleźć w dokumentacji: (null-safety)

Shahzin KS
źródło
Działa to tylko wtedy, gdy b jest zmienną lokalną. A co ze zmiennymi klas?
Warpzit
5

if let komunikat.

Swift's Optional Binding(tak zwana if-letinstrukcja) służy do sprawdzenia, czy opcja opcjonalna zawiera wartość, a jeśli tak, do udostępnienia tej wartości jako tymczasowej stałej lub zmiennej. Tak więc instrukcja Optional Bindingdla if-letinstrukcji wygląda następująco:

if-letOświadczenie Swifta :

let b: Int? = 50

if let a = b {
    print("Good news!")
} else {
    print("Equal to 'nil' or not set")
}

/*  RESULT: Good news!  */

W Kotlinie, podobnie jak w Swift, aby uniknąć awarii spowodowanych próbą uzyskania dostępu do wartości null, gdy nie jest to oczekiwane, przewidziana jest specyficzna składnia (jak b.let { }w drugim przykładzie) do prawidłowego rozpakowania nullable types:

Kotlin odpowiednik 1if-let wypowiedzi Swifta :

val b: Int? = null
val a = b

if (a != null) { 
    println("Good news!")
} else { 
    println("Equal to 'null' or not set")
}

/*  RESULT: Equal to 'null' or not set  */

letFunkcja Kotlina , gdy jest używana w połączeniu z operatorem bezpiecznego wywołania ?:, zapewnia zwięzły sposób obsługi wyrażeń dopuszczających wartość null.

Kotlin odpowiednik 2 (funkcja let inline i operator Elvisa)if-let instrukcji Swift :

val b: Int? = null

val a = b.let { nonNullable -> nonNullable } ?: "Equal to 'null' or not set"
println(a)

/*  RESULT: Equal to 'null' or not set  */

wprowadź opis obrazu tutaj

guard let komunikat.

guard-letOświadczenie w Swift jest proste i potężne. Sprawdza, czy występuje warunek i jeśli zostanie oszacowany jako fałszywy, elsewykonywana jest instrukcja, która normalnie kończy działanie metody.

Przyjrzyjmy się stwierdzeniu Swifta guard-let:

let b: Int? = nil

func testIt() {
    guard let a = b else {
        print("Equal to 'nil' or not set")
        return
    }
    print("Good news!")
}
testIt()

/*  RESULT: Equal to 'nil' or not set  */

Podobny efekt Kotlinaguard-let wypowiedzi Swifta :

W przeciwieństwie do Swifta, w Kotlinie nie ma żadnego oświadczenia strażnika . Możesz jednak użyć Elvis Operator-, ?:aby uzyskać podobny efekt.

val b: Int? = 50

fun testIt() {
    val a = b ?: return println("Equal to 'null' or not set")
    return println("Good news!")
}
testIt()

/*  RESULT: Good news!  */

Mam nadzieję że to pomoże.

Andy Fedoroff
źródło
4

Oto jak wykonać kod tylko wtedy, gdy namenie jest null:

var name: String? = null
name?.let { nameUnwrapp ->
    println(nameUnwrapp)  // not printed because name was null
}
name = "Alex"
name?.let { nameUnwrapp ->
    println(nameUnwrapp)  // printed "Alex"
}
Александр Яковенко
źródło
if name == pusty kod w {} nie jest wykonywany, jeśli nazwa jako String - kod wykonaj: nameUnwrapp == nazwa.
Александр Яковенко
1
Nie sądzę, aby o to pytał OP, jestem pewien, że OP już wie, co letrobi, ale pytanie dotyczy elsestrategii, która jest wykonywana, jeśli obiekt, na którym letjest wywoływany, jest null. Swift ma to w bardziej naturalny (dyskusyjny) sposób. Ale zrobiwszy dużo zarówno Kotlin, jak i Swift, chciałbym, aby Kotlin miał proste rozpakowanie, jak robi to Swift.
kalehv
2

Oto mój wariant, ograniczony do bardzo powszechnego przypadku „jeśli nie zerowy”.

Przede wszystkim zdefiniuj to gdzieś:

inline fun <T> ifNotNull(obj: T?, block: (T) -> Unit) {
    if (obj != null) {
        block(obj)
    }
}

Prawdopodobnie powinno internal , aby uniknąć konfliktów.

Teraz przekonwertuj ten kod Swift:

if let item = obj.item {
    doSomething(item)
}

Do tego kodu Kotlin:

ifNotNull(obj.item) { item -> 
    doSomething(item)
}

Zauważ, że jak zawsze w przypadku bloków w Kotlinie, możesz porzucić argument i użyć it:

ifNotNull(obj.item) {
    doSomething(it)
}

Ale jeśli blok ma więcej niż 1-2 wiersze, prawdopodobnie najlepiej jest to wyraźnie określić.

To jest tak podobne do Swift, jak mogłem znaleźć.

noamtm
źródło
0

W kotlinie istnieje podobny sposób osiągnięcia stylu Swifta, jeśli - pozwolę

if (val a = b) {
    a.doFirst()
    a.doSecond()
}

Można również przypisać wiele wartości dopuszczających wartość null

if (val name = nullableName, val age = nullableAge) {
    doSomething(name, age)
}

Takie podejście będzie bardziej odpowiednie, jeśli wartości dopuszczające wartość null są używane więcej niż 1 razy. Moim zdaniem pomaga to z punktu widzenia wydajności, ponieważ wartość zerowa zostanie sprawdzona tylko raz.

źródło: Dyskusja Kotlin

Richard
źródło
1
Należy pamiętać, że pokazane podejście nie jest obecnie kompilowane. To tylko sugestia, jak zmienić język Kotlin, aby uporać się z tym problemem. Dlatego nie jest to poprawne rozwiązanie.
Peter F
0

Dodaję tę odpowiedź, aby wyjaśnić zaakceptowaną odpowiedź, ponieważ jest za duża na komentarz.

Ogólny wzorzec jest taki, że możesz użyć dowolnej kombinacji funkcji zakresu dostępnych w Kotlin oddzielonych operatorem Elvisa w następujący sposób:

<nullable>?.<scope function> {
    // code if not null
} :? <scope function> {
    // code if null
}

Na przykład:

val gradedStudent = student?.apply {
    grade = newGrade
} :? with(newGrade) {
    Student().apply { grade = newGrade }
}
Sir Codesalot
źródło
-1

Moim zdaniem najczystsza opcja jest taka

Szybki:

if let a = b.val {

} else {

}

Kotlin

b.val.also { a ->

} ?: run {

}
Stiiv
źródło
-1

Szybkie oświadczenie if let w Kotlinie

Krótka odpowiedź brzmi: użyj prostego IF-ELSE, ponieważ do czasu tego komentarza nie ma odpowiednika w Kotlin LET,

    if(A.isNull()){
// A is null
    }else{
// A is not null
    }
bastami82
źródło