Компилятор Kotlin оптимизирует хвостовые рекурсивные вызовы с несколькими перехватами. Рассмотрим функцию ранга для поиска индекса элемента в отсортированном массиве, реализованную следующим образом с использованием хвостовой рекурсии и теста для нее:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
fun rank(k: Int, arr: Array<Int>): Int { tailrec fun rank(low: Int, high: Int): Int { if (low > high) { return - 1 } val mid = (low + high) / 2 return when { (k < arr[mid]) -> rank(low, mid) (k > arr[mid]) -> rank(mid + 1 , high) else -> mid } } return rank( 0 , arr.size - 1 ) } @Test fun rankTest() { val array = arrayOf( 2 , 4 , 6 , 9 , 10 , 11 , 16 , 17 , 19 , 20 , 25 ) assertEquals(- 1 , rank( 100 , array)) assertEquals( 0 , rank( 2 , array)) assertEquals( 2 , rank( 6 , array)) assertEquals( 5 , rank( 11 , array)) assertEquals( 10 , rank( 25 , array)) } |
IntelliJ предоставляет отличную функцию для отображения байт-кода любого кода Kotlin, в соответствии со следующим снимком экрана:
Эквивалент Kotlin типа байт-кода, который генерирует компилятор Kotlin, выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
fun rankIter(k: Int, arr: Array<Int>): Int { fun rankIter(low: Int, high: Int): Int { var lo = low var hi = high while (lo <= hi) { val mid = (lo + hi)/ 2 if (k < arr[mid]) { hi = mid } else if (k > arr[mid]){ lo = mid + 1 } else { return mid } } return - 1 } return rankIter( 0 , arr.size - 1 ) } |
хвостовые вызовы были переведены в простой цикл.
Есть несколько уловов, которые я мог видеть, хотя:
1. Компилятору должно быть явно сказано, какие вызовы являются хвостово-рекурсивными, с использованием модификатора tailrec.
2. Добавление модификатора tailrec к нерекурсивной функции не приводит к ошибкам компилятора, хотя на этапе компиляции появляется предупреждение
Смотреть оригинальную статью здесь: Kotlin — оптимизация хвостовой рекурсии
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |