【问题标题】:How can I create a new specific type of class when extending a trait in scala在scala中扩展特征时如何创建新的特定类型的类
【发布时间】:2018-01-31 16:43:01
【问题描述】:

我有一个特点,其中(除其他外)我想要一个方法来创建类的新实例,然后还有其他方法使用该类的实例。

我的代码的一个非常精简的版本是:

trait A {
  def prev: A
  def get(end: A): A
}

class B extends A {
  def prev: B = new B()
  def get(end: B): B = end.prev
}

我想在这里展示的是,next 将返回该类的一个新实例(实际上带有一些新的构造函数参数),get 方法将在内部使用 next(以及其他逻辑)

上面的问题是编译器说“class B must implement abstract member get(end: A): A”,这是合理的。

我尝试使用类型边界来解决它:

trait A {
  def prev: A
  def get(end: A): A
}

case class B extends A {
  def prev[TX <: A]: TX = new B()
  def get[TX <: A](end: TX): TX = end.prev
}

但现在错误是new B() 上的“B 类型的表达式不符合预期的 TX 类型”,end.prev 上的“A 类型的表达式不符合预期的 TX 类型”

我不明白为什么这是个问题,因为接下来会返回一个 B,它是 A 的子类型,也就是 TX。

有没有办法实现我希望在这里做的事情?


如果以上所有内容看起来都过于抽象,请提供一些上下文。我正在实现一个循环双向链表,因为我找不到类似的东西。特征包括:

trait Circular[T] {
  // Nodes in the list from the current position up to but NOT INCLUDING the end
  def toStream(end: Circular[T]): Stream[Circular[T]]
  def prev: Circular[T]
  ...

我的班级看起来像:

case class Node[T](val data: T, var prev: Node[T], var next: Node[T])

case class CircularList[T](first: Node[T], last: Node[T], current: Node[T]) 
  extends Circular[T] {

  // Nodes in the list from the current position up to but not including the end
  def toStream(end: CircularList[T]): Stream[CircularList[T]] = {
    @tailrec
    def toStreamRec(end: CircularList[T], acc: Stream[CircularList[T]]): Stream[CircularList[T]] = {
      if (this == end) {
        acc
      } else {
        toStreamRec(end.prev, Stream.cons(end.prev, acc))
      }
    }
    toStreamRec(end, Stream.empty)
  }

  def prev: CircularList[T] = new CircularList[T](first, last, current.prev)
  ...

所以在我的缩减示例中,toStream 映射到 get。

【问题讨论】:

    标签: scala type-bounds


    【解决方案1】:

    你想要的是一个叫做F-bound generic的东西。代码如下:

    trait Base[T <: Base[T]] {
      def next: T
      def get(end: T): T
    }
    
    class Chlid extends Base[Child] {
      def next: Chlid = new Chlid()
      def get(end: Chlid): Chlid = end.next
    }
    

    您的代码无法编译,因为

    def get(end: B): B
    

    不是

    的覆盖
    def get(end: A): A
    

    因为原始方法接受 A 类型的对象,而您的方法只需要更窄的类型 B


    对于您的Circular 示例,您需要类似

    trait Circular[T, C <: Circular[T, C]] {
      // Nodes in the list from the current position up to but NOT INCLUDING the end
      def toStream(end: C): Stream[C]
    
      def next: C
    }
    
    case class Node[T](val data: T, var prev: Node[T], var next: Node[T])
    
    case class CircularList[T](first: Node[T], last: Node[T], current: Node[T]) extends Circular[T, CircularList[T]] {
    
      // Nodes in the list from the current position up to but not including the end
      def toStream(end: CircularList[T]): Stream[CircularList[T]] = {
        @tailrec
        def toStreamRec(end: CircularList[T], acc: Stream[CircularList[T]]): Stream[CircularList[T]] = {
          if (this == end) {
            acc
          } else {
            toStreamRec(end.prev, Stream.cons(end.prev, acc))
          }
        }
    
        toStreamRec(end, Stream.empty)
      }
    
      def prev: CircularList[T] = new CircularList[T](first, last, current.prev)
    
      override def next: CircularList[T] = ???
    }
    

    【讨论】:

    • 谢谢!这为我节省了大量时间。
    猜你喜欢
    • 2019-05-11
    • 1970-01-01
    • 2016-11-28
    • 1970-01-01
    • 2016-07-04
    • 1970-01-01
    • 2016-09-13
    • 1970-01-01
    • 2015-06-03
    相关资源
    最近更新 更多