为什么scala @tailrec不能在Option.flatMap上使用?

前端之家收集整理的这篇文章主要介绍了为什么scala @tailrec不能在Option.flatMap上使用?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
scala中,以下两个函数用于完全相同的目的:

@tailrec
final def fn(str: String): Option[String] = {
  Option(str).filter(_.nonEmpty).flatMap { v =>
    fn(v.drop(1))
  }
}

@tailrec
final def fn2(str: String): Option[String] = {
  Option(str).filter(_.nonEmpty) match {
    case None    => None
    case Some(v) => fn2(v.drop(1))
  }
}

但是@tailrec仅适用于第二种情况,在第一种情况下它将生成以下错误

Error: could not optimize @tailrec annotated method fn: it contains a
recursive call not in tail position
Option(str).filter(_.nonEmpty).flatMap { v =>

为什么会出现这个错误?为什么这两个代码生成不同种类的JVM字节码

解决方法

要使fn成为尾递归,递归调用必须是函数中的最后一个操作.如果将fn传递给另一个函数(如flatMap),那么另一个函数可以在调用fn后自由执行其他操作,因此编译器无法确定它是尾递归的.

在某些情况下,编译器可以检测到调用fn是另一个函数中的最后一个操作,但在一般情况下不是.并且这将依赖于该其他函数的特定实现,因此如果其他函数被更改,则tailrec注释可能变得无效,这是不期望的依赖性.

猜你在找的Scala相关文章