我的用例更复杂,但基本上下面是我想要实现的简化示例(我的原始代码是针对akka-stream):
offset := 0
//pump data
def pump(): Unit = {
elem := poller.getNumberFromOffset(offset)
elem match {
case null => doSomething()
case Completed => doSomethingElse()
case _ =>
offset += 1
//check if the element is matched with a pre-supplied selector/filter function
if(filterFunc(elem)) {
doSomething2()
} else {
//if the element doesn't match; increase offset and try again; can sleep for a while here
pump()
}
}
}
问题是pump()函数可能导致堆栈溢出(因为泵函数在特定条件下被反复调用)。
我可以将函数写入非递归版本,如下所示:
offset := 0
//pump data
def pump(): Unit = {
elem := poller.getNumberFromOffset(offset)
while(elem != null && elem != Completed && !filterFunc(elem)) {
offset += 1
elem = poller.getNumberFromOffset(offset)
}
elem match {
case null => doSomething()
case Completed => doSomethingElse()
case _ =>
offset += 1
doSomething2()
}
}
但是我的用例要复杂得多;所以我真的很想使用递归函数,而不是将现有代码转换为while / for循环。
我的问题是“我应该这样做”,如果我只是简单地在第一个例子中加上@tailrec注释,那么scala编译器就会将泵视为尾递归函数(@tailrec def pump():Unit = {})。在我的情况下,pump()函数应该在固定间隔后分开调用;所以堆栈框架在这里真的没有必要。
感谢。
答案 0 :(得分:1)
如果你放@tailrec
并且编译器允许你运行它,这意味着你的代码片段有资格进行尾递归优化。内部scala编译器会将尾递归代码转换为循环。我不认为尾递归函数会导致stackoverflow错误。所以你的pump()函数如果满足@tailrec
则不会导致stackoverflow。