加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – @tailrec错误“递归调用目标超类型”

发布时间:2020-12-16 09:52:59 所属栏目:安全 来源:网络整理
导读:应用@tailrec我从 scala编译器得到错误:“无法优化@tailrec带注释的方法get:它包含一个针对超类型case _ = tail.get(n-1)”的递归调用.有人可以解释为什么会这样吗? trait List[T] { def isEmpty: Boolean def head: T def tail: List[T] def get(n: Int)
应用@tailrec我从 scala编译器得到错误:“无法优化@tailrec带注释的方法get:它包含一个针对超类型case _ => tail.get(n-1)”的递归调用.有人可以解释为什么会这样吗?

trait List[T] {
  def isEmpty: Boolean
  def head: T
  def tail: List[T]
  def get(n: Int): T
}

class Cons[T](val head: T,val tail: List[T]) extends List[T]{
  def isEmpty = false
  @tailrec
  final def get(n: Int) =
    n match {
      case 0 => head
      case _ => tail.get(n-1)
    }
}

class Nil[T] extends List[T]{
  def isEmpty = true
  def head = throw new NoSuchElementException("Nil.head")
  def tail = throw new NoSuchElementException("Nil.tail")
  final def get(n: Int): T = throw new IndexOutOfBoundsException
}

object Main extends App{
  println(new Cons(4,new Cons(7,new Cons(13,new Nil))).get(3))
}

解决方法

试着想象一下这里发生了什么,以及你要求编译器做什么.粗略的尾部调用优化将方法调用转换为循环,获取方法的参数并将它们转换为在循环的每次迭代中重新分配的变量.

这里有两个这样的“循环变量”:n和调用get方法的列表单元本身,实际上是在方法体中. n的下一个值很好:它是n – 1,也是Int.列表单元格的下一个值(尾部)是一个问题,但是:它具有类型Cons [T],但尾部只有类型List [T].

因此,编译器无法将其转换为循环,因为无法保证tail是一个Cons [T] – 当然,在列表的末尾,它是一个Nil.

“修复”它的一种方法是:

case class Cons[T](val head: T,val tail: List[T]) extends List[T] {
  def isEmpty = false
  @tailrec
  final def get(n: Int) =
    n match {
      case 0 => head
      case _ => tail match {
        case c @ Cons(_,_) => c.get(n - 1)
        case nil @ Nil() => nil.get(n - 1)
      }
    }
}

(如果Cons和Nil都是案例类,则可以工作 – 但是您可能希望在T中使Nil成为案例对象和List [T]协变量.)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读