Scala特质方法无法调用伴生对象方法编译报错排查
解决Scala中StreamRed特质无法访问伴生对象方法的问题
你遇到的问题核心是Scala特质无法直接访问其伴生对象的成员——cons和empty是定义在StreamRed伴生对象里的方法,而特质StreamRed的作用域默认不会自动引入这些方法,所以编译器会提示找不到它们。下面给你两种解决思路,顺便还帮你修复了toList方法里的一个小bug:
方法1:使用伴生对象限定名调用
直接在take和drop方法里用StreamRed.cons和StreamRed.empty来调用伴生对象的方法,让编译器能准确定位到这些方法:
import scala.annotation.tailrec object Run extends App { sealed trait StreamRed[+A] { def headOption: Option[A] = this match { case Empty => None case Cons(h,t) => Some(h()) } def toList: List[A] = { @tailrec def toListRec(stream: StreamRed[A], accumulated: List[A]): List[A] = stream match { // 修复:原来匹配的是this,应该是传入的stream参数 case Cons(h,t) => toListRec(t(), h()::accumulated) case _ => accumulated } toListRec(this, List()).reverse } def take(n: Int): StreamRed[A] = this match { case Cons(h, t) if n > 1 => StreamRed.cons(h(), t().take(n - 1)) // 用StreamRed限定调用 case Cons(h, _) if n == 1 => StreamRed.cons(h(), StreamRed.empty) // 用StreamRed限定调用 case _ => StreamRed.empty // 用StreamRed限定调用 } @tailrec def drop(n: Int): StreamRed[A] = this match { case Cons(_,t) if n > 0 => t().drop(n-1) case _ => StreamRed.empty // 用StreamRed限定调用 } } case object Empty extends StreamRed[Nothing] case class Cons[+A](h: () => A, t: () => StreamRed[A]) extends StreamRed[A] object StreamRed { def cons[A](hd: => A, tl: => StreamRed[A]): StreamRed[A] = { lazy val head = hd lazy val tail = tl Cons(() => head, () => tail) } def empty[A]: StreamRed[A] = Empty def apply[A](as: A*): StreamRed[A] = if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*)) } }
方法2:在特质内部导入伴生对象成员
如果觉得每次写StreamRed.太繁琐,可以在特质StreamRed的顶部导入伴生对象的所有成员,这样就能直接使用cons和empty了:
import scala.annotation.tailrec object Run extends App { sealed trait StreamRed[+A] { import StreamRed._ // 导入伴生对象的所有成员,直接使用cons和empty def headOption: Option[A] = this match { case Empty => None case Cons(h,t) => Some(h()) } def toList: List[A] = { @tailrec def toListRec(stream: StreamRed[A], accumulated: List[A]): List[A] = stream match { // 修复了this匹配的bug case Cons(h,t) => toListRec(t(), h()::accumulated) case _ => accumulated } toListRec(this, List()).reverse } def take(n: Int): StreamRed[A] = this match { case Cons(h, t) if n > 1 => cons(h(), t().take(n - 1)) case Cons(h, _) if n == 1 => cons(h(), empty) case _ => empty } @tailrec def drop(n: Int): StreamRed[A] = this match { case Cons(_,t) if n > 0 => t().drop(n-1) case _ => empty } } case object Empty extends StreamRed[Nothing] case class Cons[+A](h: () => A, t: () => StreamRed[A]) extends StreamRed[A] object StreamRed { def cons[A](hd: => A, tl: => StreamRed[A]): StreamRed[A] = { lazy val head = hd lazy val tail = tl Cons(() => head, () => tail) } def empty[A]: StreamRed[A] = Empty def apply[A](as: A*): StreamRed[A] = if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*)) } }
额外修复说明
你原来的toList方法里,toListRec函数错误地匹配了this而不是传入的stream参数,这会导致递归永远处理初始的流对象,无法遍历整个序列。上面的代码已经把这个bug修复,改成了匹配stream参数。
内容的提问来源于stack exchange,提问作者evam
相关产品推荐
相关产品推荐

