尾部递归(@tailrec)递归函数与非递归函数scala堆栈溢出错误?

尾部递归(@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()

我的用例更复杂,但下面是我试图实现的简化示例,我的原始代码是针对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()
            }
    }
}
问题是,泵函数可能会导致堆栈溢出,因为泵函数会针对特定条件反复调用

我可以将函数写入非递归版本,如下所示:

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