【问题标题】:Recursive call not in tail position递归调用不在尾部位置
【发布时间】:2015-08-11 02:14:48
【问题描述】:

假设我定义了以下函数:

final def myFunc[T](list: List[T]): List[T] = list match {
        case h :: t =>
            h :: myFunc(t)
        case _ =>
            Nil
    } 

当我添加 tailrec 注释时,编译器给我以下错误:

无法优化 @tailrec 注释的方法 myFunc:它包含一个 递归调用不在尾部位置:^Nil.

我对 Nil 的声明如何成为递归调用感到困惑?

【问题讨论】:

  • 不是Nil,而是::,这意味着对于堆栈中的每个调用,您仍然必须将部分结果连接到h,这就是为什么此方法不是尾递归的原因.作为测试,尝试 case h :: t => myFunc(t) 并打开 tailrec 注释。

标签: scala


【解决方案1】:

问题不在于Nil 而在于h :: myFunc(t),因为myFunc(t) 不是最后一次调用。最后一个电话是在myFunc(t) 的结果上调用运算符::。这就是函数不是尾递归的原因。

【讨论】:

  • 猜猜是编译器消息误导了。
  • 不相关但可能有用的信息:由于 Scala 运算符关联性规则,h :: myFunc(t)myFunc(t).::(h) 相同。当你这样重写它时,更明显的是递归调用不在尾部位置。幸运的是,Scala 中的运算符关联规则非常简单:如果运算符以 : 字符结尾,则它是右关联的,否则是左关联的。所以需要特别注意#::::+:等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-23
  • 2015-06-02
  • 2016-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多