Котлин: Что означает «return @»?

#android #rx-java #kotlin

#Android #rx-java #котлин

Вопрос:

Я использую RxJava в одном из своих проектов, я преобразовал один из своих классов в Kotlin с помощью плагина Android Studio, и в одном из map flatMap lambda (Func1 в Java) промежуточные возвраты выглядят следующим образом @Func1 .

Я понятия не имею, что это значит.

 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)
})
  

Ответ №1:

В Kotlin return@label синтаксис используется для указания, из какой функции из нескольких вложенных возвращается этот оператор.

Он работает с литералами функций (лямбды) и локальными функциями. Немаркированные return операторы возвращаются из ближайшего (то есть самого внутреннего) окружения fun (игнорируя лямбды). Рассмотрим эту функцию:

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

Здесь return завершится выполнение foo , а не только лямбда-выражения.

Но если вы хотите выполнить возврат из любой другой функции (лямбда или внешней fun ), вы должны указать ее в качестве метки в return инструкции:

 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"]
  

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


Существует также аналогичный синтаксис для qualified this , который используется для ссылки на приемники внешних областей: this@outer .

Комментарии:

1. Спасибо! Было бы неплохо, если бы официальные документы Kotlin описали это немного подробнее с примерами, как вы сделали здесь.

Ответ №2:

return@name определяет, для какой инструкции closure return следует применять.

В Kotlin вы можете вызвать return из вложенного замыкания, чтобы завершить внешнее замыкание. В Java это невозможно.

Обычно это значение можно опустить @name .

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

Комментарии:

1. Если код написан внутри тела функции, @Func1 его нельзя опустить.

2. Не могли бы вы подробнее рассказать о том, при каких условиях @Func1 можно опустить? Я попытался использовать выражение something.flatMap(...) в объявлении верхнего уровня, но я получил ошибку » return здесь не разрешено».

3. Спасибо! Оба ответа @hotkey и mklimek верны, ответ hotkey просто немного более сложный, я поддерживаю оба и проверяю горячие клавиши 🙂

4. Возможно ли использовать это для when (эквивалент коммутатора на Kotlin)? Много раз я хочу разорвать его, когда отступ слишком велик…