Kotlin编译器通过一些捕获来优化尾部递归调用 。 考虑一个rank函数来搜索排序数组中元素的索引,使用尾部递归及其测试通过以下方式实现:
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如下:
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修饰符不会生成编译器错误,尽管在编译步骤中确实会出现警告
翻译自: https://www.javacodegeeks.com/2017/12/kotlin-tail-recursion-optimization.html