Kotlin - 为什么这个函数不符合尾递归的条件?
Kotlin - Why is this function ineligible for tail recursion?
下例中的函数send()
递归调用自身:
internal inner class RouteSender(
val features: List<Feature>,
val exchange: GrpcUniExchange<Point, RouteSummary>
) {
var result: AsyncResult<RouteSummary>? = null // Set in stub for recordRoute.
fun send(numPoints: Int) {
result?.let {
// RPC completed or err'd before sending completed.
// Sending further requests won't error, but they will be thrown away.
return
}
val index = random.nextInt(features.size)
val point = features[index].location
println("Visiting point ${RouteGuideUtil.getLatitude(point)}, " +
"${RouteGuideUtil.getLongitude(point)}")
exchange.write(point)
if (numPoints > 0) {
vertx.setTimer(random.nextInt(1000) + 500L) { _ ->
send(numPoints - 1)
}
} else {
exchange.end()
}
}
}
可以改写成最后执行的操作是对自身的递归调用:
...
if (numPoints <= 0) {
exchange.end()
} else {
vertx.setTimer(random.nextInt(1000) + 500L) { _ ->
send(numPoints - 1)
}
}
...
然而,如果我将其标记为 tailrec
函数,我会收到一条警告,指出递归调用不是尾调用。这不会停止编译成功的 运行 程序。但是,为什么这不是尾调用?
To be eligible for the tailrec
modifier, a function must call itself
as the last operation it performs. You cannot use tail recursion when
there is more code after the recursive call, and you cannot use it
within try/catch/finally blocks.
这不在 try/catch/finally 块内,递归调用后没有更多代码。这意味着此代码块不符合尾递归优化的条件是什么?
我会尝试回答我自己的问题,因为它没有 return 值。根据 this 的讨论,我能想到的就这些了。想法?
虽然您的方法看起来包含对自身的调用,但它实际上根本不是递归方法。
对 send
的调用出现在闭包内。这意味着它不会立即被调用。它只会在闭包本身被调用时被调用。在您的情况下,这是由计时器完成的。它将发生在当前调用堆栈之外,甚至可能发生在当前线程之外。
无论如何,最后一次调用是对vertx.setTimer
的调用。
Kotlin 允许内联闭包函数,它用于许多它自己的库函数,例如 forEach。如果从内联闭包中调用 tailrec 可能会起作用,毕竟 return 来自内联闭包 returns 来自外部函数。
但是,如上所述,这是一个计时器回调函数,因此根据定义它不能是内联调用,也不是尾递归。
下例中的函数send()
递归调用自身:
internal inner class RouteSender(
val features: List<Feature>,
val exchange: GrpcUniExchange<Point, RouteSummary>
) {
var result: AsyncResult<RouteSummary>? = null // Set in stub for recordRoute.
fun send(numPoints: Int) {
result?.let {
// RPC completed or err'd before sending completed.
// Sending further requests won't error, but they will be thrown away.
return
}
val index = random.nextInt(features.size)
val point = features[index].location
println("Visiting point ${RouteGuideUtil.getLatitude(point)}, " +
"${RouteGuideUtil.getLongitude(point)}")
exchange.write(point)
if (numPoints > 0) {
vertx.setTimer(random.nextInt(1000) + 500L) { _ ->
send(numPoints - 1)
}
} else {
exchange.end()
}
}
}
可以改写成最后执行的操作是对自身的递归调用:
...
if (numPoints <= 0) {
exchange.end()
} else {
vertx.setTimer(random.nextInt(1000) + 500L) { _ ->
send(numPoints - 1)
}
}
...
然而,如果我将其标记为 tailrec
函数,我会收到一条警告,指出递归调用不是尾调用。这不会停止编译成功的 运行 程序。但是,为什么这不是尾调用?
To be eligible for the
tailrec
modifier, a function must call itself as the last operation it performs. You cannot use tail recursion when there is more code after the recursive call, and you cannot use it within try/catch/finally blocks.
这不在 try/catch/finally 块内,递归调用后没有更多代码。这意味着此代码块不符合尾递归优化的条件是什么?
我会尝试回答我自己的问题,因为它没有 return 值。根据 this 的讨论,我能想到的就这些了。想法?
虽然您的方法看起来包含对自身的调用,但它实际上根本不是递归方法。
对 send
的调用出现在闭包内。这意味着它不会立即被调用。它只会在闭包本身被调用时被调用。在您的情况下,这是由计时器完成的。它将发生在当前调用堆栈之外,甚至可能发生在当前线程之外。
无论如何,最后一次调用是对vertx.setTimer
的调用。
Kotlin 允许内联闭包函数,它用于许多它自己的库函数,例如 forEach。如果从内联闭包中调用 tailrec 可能会起作用,毕竟 return 来自内联闭包 returns 来自外部函数。
但是,如上所述,这是一个计时器回调函数,因此根据定义它不能是内联调用,也不是尾递归。