尾部递归(@tailrec)递归函数与非递归函数scala堆栈溢出错误?
我的用例更复杂,但下面是我试图实现的简化示例,我的原始代码是针对akka stream的:尾部递归(@tailrec)递归函数与非递归函数scala堆栈溢出错误?,scala,recursion,stack-overflow,tail-recursion,akka-stream,Scala,Recursion,Stack Overflow,Tail Recursion,Akka Stream,我的用例更复杂,但下面是我试图实现的简化示例,我的原始代码是针对akka stream的: offset := 0 //pump data def pump(): Unit = { elem := poller.getNumberFromOffset(offset) elem match { case null => doSomething() case Completed => doSomethingElse()
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()
}
}
}
问题是,泵函数可能会导致堆栈溢出,因为泵函数会针对特定条件反复调用
我可以将函数写入非递归版本,如下所示:
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={},有什么区别吗。在我的情况下,泵函数应该单独调用/在固定间隔后调用;因此,这里确实不需要堆栈帧
谢谢。如果您放置@tailrec,并且编译器允许您运行它,这意味着您的代码片段符合尾部递归优化的条件。在内部,scala编译器将尾部递归代码转换为循环。我不认为尾部递归函数会导致stackoverflow错误。因此,如果泵函数满足@tailrec,则不会导致stackoverflow。如果我只在第一个示例中添加@tailrec注释,有什么区别吗?没有。@tailrec注释没有区别。尾部递归方法总是经过优化的。更准确地说:满足以下条件的方法。@tailrec注释所做的唯一一件事是,如果该方法不是尾部递归的,则生成编译器错误。我质疑你的模式匹配是否为空。相反,我会将您可能的空值包装在中。示例:选项[String]{null}==None