Понимание доходности Kotlin - PullRequest
5 голосов
/ 12 марта 2019

Я не вижу четкого определения ключевого слова Доходность в 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]

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

  • Что значит приостановка?
  • В каких случаях это может быть выгодно?

Я из мира Java, поэтому немного сложно понять эту концепцию.

Заранее спасибо.

Ответы [ 2 ]

6 голосов
/ 13 марта 2019

Вы можете думать о 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 && count.get() <= 5) {
           state += 2;
           return state;
        }
        else {
           state *= 3;
           return state;
        }
    }
}

В классе Java мы поддерживаем явное состояние, имея две переменные: count и state. Комбинация sequence и yield позволяет неявно поддерживать это состояние.

2 голосов
/ 13 марта 2019

Давайте рассмотрим пример, в котором вы можете сгенерировать следующий элемент последовательности, но вы не видите простого способа реализации итератора 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

...