Понимание функции доходности Kotlin

#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