Kotlin – 为什么这个函数不适合尾递归?
下面的例子中的函数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
函数, tailrec
发出递归调用不是尾调用的警告。 这并没有停止编译程序的成功运行。 但是,为什么这不是一个尾巴?
该文件说:
要符合
tailrec
修饰符的条件,函数必须调用它自己作为它执行的最后一个操作。 在递归调用之后有更多的代码时,您不能使用尾递归,并且不能在try / catch / finally块中使用它。
这不在try / catch / finally块内,递归调用后没有更多的代码。 这是什么意思,这个代码块不适合尾递归优化?
我会刺探回答我自己的问题,因为它没有回报价值。 基于这个讨论,这是我所能想到的。 思考?
虽然你的方法似乎包含一个对自身的调用,但它实际上并不是一个递归方法。
send
的呼叫出现在封闭内。 这意味着它不会立即被调用。 只有在调用闭包本身时才会调用它。 在你的情况下,这是由一个计时器。 它将发生在当前调用堆栈之外,甚至可能在当前线程之外。
在任何情况下,最后的调用是对vertx.setTimer
的调用。
Kotlin允许内联闭包函数,它使用了一些自己的库函数,比如forEach。 tailrec可能工作,如果它是从一个内联闭包调用,所有从内联闭包返回从外部函数返回。
但是,如上所述,这是一个定时器回调函数,所以它可以按照定义不是内联调用,而不是尾递归。