#kotlin #yield #kotlin-android-extensions #kotlin-coroutines
#kotlin #доходность #kotlin-android-расширения #kotlin-сопрограммы
Вопрос:
Я не вижу очень четкого определения yield
функции в Kotlin.
В примере по ссылке выше упоминается не так много, но следующее,
val sequence = sequence {
val start = 0
// yielding a single value
yield(start)
// yielding an iterable
yieldAll(1..5 step 2)
// yielding an infinite sequence
yieldAll(generateSequence(8) { it * 3 })
}
println(sequence.take(7).toList()) // [0, 1, 3, 5, 8, 24, 72]
Но приведенный выше пример не указывает на важность yield.
- Что означает, что это приостанавливающая функция?
- В каких сценариях это может быть выгодно?
Ответ №1:
Вы можете думать о yield()
как о «вернитесь и в следующий раз начните с того места, где вы остановились«.:
val sequence = sequence {
val start = 0
yield(start) // first return
yieldAll(1..5 step 2) // if called again, will start from here
yieldAll(generateSequence(8) { it * 3 }) // if called more that six times, start from here
}
Она создает конечный автомат и прочее, но вы можете перевести это на что-то вроде следующего в Java:
class Seq {
private AtomicInteger count = new AtomicInteger(0);
private int state = 0;
public int nextValue() {
if (count.get() == 0) {
return state;
}
else if (count.get() >= 1 amp;amp; count.get() <= 5) {
state = 2;
return state;
}
else {
state *= 3;
return state;
}
}
}
В классе Java мы поддерживаем явное состояние, имея две переменные: count
и state
. Комбинация sequence
и yield
позволяет поддерживать это состояние неявно.
Обратите внимание, что yield()
это приостанавливающая функция, поэтому она может быть вызвана только из другой suspend
функции или из сопрограммы.
Комментарии:
1. Так это связано с сопрограммами или нет?
2. Я думаю, вам следует увеличивать количество вызовов для каждого.
Ответ №2:
Давайте рассмотрим пример, в котором вы можете сгенерировать следующий элемент последовательности, но вы не видите простого способа реализовать Java-итератор.
fun fibonacci() = sequence {
var a_0 = 1
var a_1 = 1
// this sequence is infinite
while(true) {
val a_n = a_0 a_1
a_0 = a_1
a_1 = a_n
//this is a suspend function call
yield(a_0)
}
}
В примере используется yield
функция для возврата следующего элемента последовательности. Функция является примером suspend
функции в Kotlin. Вызов функции приостанавливает выполнение sequence{..}
блока, поэтому стек вызовов свободен.
Допустим, мы делаем следующее
fibonacci().take(10).forEach{
println(it)
}
Каждая итерация forEach
цикла возобновляет sequence{..}
блок из предыдущего yield
вызова функции и позволяет ему выполняться до следующего yield
вызова функции. Поток выполнения будет смешивать forEach
итерации цикла с sequence{..}
вычислением блока. Вы можете попробовать написать то же самое, что и Java Iterator
, чтобы почувствовать, что делает компилятор Kotlin за кулисами.
suspend
функции в Kotlin минималистичны с точки зрения языка и стандартной библиотеки, остальное может быть реализовано в библиотеках. Я рекомендую проверить kotlinx.coroutines
библиотеку для получения дополнительной информации о внутренней части, примерах и документации https://github.com/Kotlin/kotlinx.coroutines
Комментарии:
1. Было бы правильно сказать, что это ничем не отличается от повторного вызова метода? т. Е. foreach(….) { fibonacci(10) } в Java?
2. Да,
.forEach{..}
это встроенная функция, на уровне байт-кода Java она будет похожа на Java foreach