Kotlin: Was bedeutet "return @"?

71

Ich verwende RxJava in einem meiner Projekte, habe eine meiner Klassen mithilfe des Android Studio-Plugins in Kotlin konvertiert und in einem der Map flatMapLambda (Func1 in Java) sieht die Zwischenrückgabe wie folgt aus @Func1.

Ich habe keine Ahnung, was das bedeutet.

something.flatMap(Func1<ArticleCriteria, Observable<Pair<String, String>>> {
    val isTemporaryClone = it.isATemporaryClone
    val isTheOriginalToken = it.tokenIsOriginalHere

    if (isTemporaryClone) {
        if (!isTheOriginalToken) {
            return@Func1 paramsError("Token is always original for temp articles")
        }

        return@Func1 mJobRunner.doNotRun(DeleteArticleJob.TAG)
                            .doOnNext(deletePersonalActionById(articleId))
    }

    runArticleJobAsync(DeleteArticleJob.TAG, it)
})
Glenn Sonna
quelle

Antworten:

103

In Kotlin wird die return@labelSyntax verwendet, um anzugeben, von welcher Funktion unter mehreren verschachtelten Funktionen diese Anweisung zurückgegeben wird.

Es funktioniert mit Funktionsliteralen (Lambdas) und lokalen Funktionen. Nicht beschriftete returnAnweisungen kehren vom nächstgelegenen (dh innersten) Gehäuse zurück fun(ohne Lambdas). Betrachten Sie diese Funktion:

fun foo(ints: List<Int>) {
    ints.forEach {
        if (it == 0) return
        print(it)
    }
}

Hier returnwird die Ausführung foonicht nur des Lambda beendet.

Wenn Sie jedoch von einer anderen Funktion (einem Lambda oder einem äußeren fun) zurückkehren möchten, müssen Sie diese als returnAnweisung bei Anweisung angeben :

fun foo(ints: List<Int>) {
    ints.forEach {
        if (it == 0) return@forEach // implicit label for lambda passed to forEach
        print(it)
    }
}

fun foo(ints: List<Int>): List<String> {
    val result = ints.map f@{
        if (it == 0) return@f "zero" // return at named label
        if (it == -1) return emptyList() // return at foo
        "number $it" // expression returned from lambda
    }
    return result
}

foo(listOf(1, -1, 1)) // []
foo(listOf(1, 0, 1)) // ["number 1", "zero", "number 1"]

Die nicht lokale Rückgabe (dh die Rückgabe von äußeren Funktionen) von einem Lambda wird nur für lokale und Inline- Funktionen unterstützt. Wenn ein Lambda nicht inline ist (oder eine Funktion in einem Objekt platziert ist), kann nicht garantiert werden, dass es nur innerhalb aufgerufen wird Die einschließende Funktion (z. B. kann sie in einer Variablen gespeichert und später aufgerufen werden) und die nicht lokale Rückgabe wären in diesem Fall nicht sinnvoll.


Es gibt auch eine ähnliche Syntax für qualifiziertethis , die verwendet wird, um Empfänger von äußeren Bereichen zu referenzieren : this@outer.

Hotkey
quelle
1
Vielen Dank! Es wäre schön gewesen, wenn die offiziellen Kotlin-Dokumente dies mit Beispielen etwas ausführlicher behandelt hätten, wie Sie es hier getan haben.
Michael Peterson
10

return@namelegt fest, für welche Abschlusserklärung returnangewendet werden soll.

In Kotlin können Sie die Rückkehr vom verschachtelten Abschluss aufrufen, um den äußeren Abschluss zu beenden. In Java ist das nicht möglich.

Normalerweise können Sie weglassen @name.

In Ihrem Beispiel können Sie es nicht weglassen, da Func1es in einer anderen Funktion verwendet wird.

klimat
quelle
1
Wenn der Code in einen Funktionskörper geschrieben ist, @Func1kann er nicht weggelassen werden.
Hotkey
Könnten Sie näher erläutern, unter welchen Bedingungen @Func1weggelassen werden kann? Ich habe versucht, den Ausdruck something.flatMap(...)in einer Deklaration der obersten Ebene zu verwenden, aber ich habe den returnFehler " ist hier nicht erlaubt" erhalten.
Hotkey
Vielen Dank! Sowohl @hotkey als auch mklimek Antworten sind richtig, Hotkeys Antwort ist nur etwas ausführlicher. Ich stimme beiden zu und überprüfe Hotkeys :)
Glenn Sonna
Ist es möglich, es für when(das Switch-Case-Äquivalent bei Kotlin) zu verwenden? Oft möchte ich es brechen, wenn die Einrückung zu viel ist ...
Android-Entwickler