代码之家  ›  专栏  ›  技术社区  ›  Bruno

如何在Scala中创建具有有界类型参数的自定义序列?

  •  5
  • Bruno  · 技术社区  · 7 年前

    考虑以下工作习惯 Seq :

    class MySeq[B](val s: Seq[B]) 
    extends Seq[B]
    with GenericTraversableTemplate[B, MySeq]
    with SeqLike[B, MySeq[B]] {
      override def companion = MySeq
    
      def iterator = s.iterator
    
      def apply(i: Int) = s(i)
    
      def length = s.length
    
      override def toString = s map { _.toString } mkString("\n")
    }
    object MySeq extends SeqFactory[MySeq] {
      implicit def canBuildFrom[B]: CanBuildFrom[Coll, B, MySeq[B]] =
           new GenericCanBuildFrom[B]
      def newBuilder[B] = new ListBuffer[B] mapResult (x => new MySeq(x.toSeq))
    }
    

    B

    class MyA
    
    class MySeq[+B <: MyA](val s: Seq[B]) 
    extends Seq[B]
    with GenericTraversableTemplate[B, MySeq]
    with SeqLike[B, MySeq[B]] {
      override def companion = MySeq  // Type Mismatch Here
    
      def iterator = s.iterator
    
      def apply(i: Int) = s(i)
    
      def length = s.length
    
      override def toString = s map { _.toString } mkString("\n")
    }
    object MySeq extends SeqFactory[MySeq] {
      implicit def canBuildFrom[B]: CanBuildFrom[Coll, B, MySeq[B]] =
           new GenericCanBuildFrom[B]
      // Type Mismatch in the line below
      def newBuilder[B] = new ListBuffer[B] mapResult (x => new MySeq(x.toSeq))
    }
    

    inferred type arguments [B] do not conform to 
    class MySeq's type parameter bounds [+B <: MyA] 
    Main.scala  line 49
    
    type mismatch;  
    found   : countvotes.structures.MySeq.type  
    required: scala.collection.generic.GenericCompanion[Seq]    
    Main.scala  line 36
    
    type mismatch;  
    found   : MySeq[B(in class MySeq)]  
    required: MySeq[B(in method newBuilder)]    
    Main.scala  line 49
    
    type mismatch;  
    found   : scala.collection.immutable.Seq[B(in method newBuilder)]  
    required: Seq[B(in class MySeq)]    
    Main.scala  line 49
    

    我试图通过向CanBuildFrom和newBuilder的类型参数添加边界来解决这个问题,但随后我收到了其他错误消息。

    是否绑定了类型参数?

    2 回复  |  直到 7 年前
        1
  •  2
  •   HTNW    7 年前

    我在第26行没有发现错误:

    override def companion = MySeq
    

    可能是其他原因造成的。

    GenericCompanion[MySeq] (的超类型 SeqFactory GenericCompanion[Coll] Coll[A] 对于任何 A (见签字人 newBuilder ). 你也不能有 MySeq[A] <: GenericTraversableTemplate[A, MySeq] 因为 genericBuilder MySeq MyA .

    MySeq[B] <: GenericTraversableTemplate[B, Seq] ,(随附免费 extends Seq ). 然后你有两个选择 companion Seq ,也可以是 s.companion ((as: MySeq[A]): Seq[A]).map(...) 将产生一个 List (在运行时;在编译时,它只是一个泛型 Seq ). 在第二种情况下,这将取决于 as.s is(同样,在运行时;compiletime将只看到 ). 你可以保留 extends SetLike 虽然

    CanBuildFrom : MySeq.canBuildFrom[A <: MyA]: CanBuildFrom[MySeq[A], A, MySeq[A]] ,并定义 MySeq#newBuilder .

    class MySeq[+B <: MyA](val s: Seq[B]) 
      extends Seq[B]
      with SeqLike[B, MySeq[B]]
    {
      override def iterator = s.iterator
      override def apply(i: Int) = s(i)
      override def length = s.length
    
      override def toString = s.map(_.toString).mkString("\n")
    
      override def companion = s.companion
      protected[this] override def newBuilder: mutable.Builder[B, MySeq[B]] = new mutable.Builder[B, MySeq[B]] {
        private[this] val base = s.genericBuilder[B]
        override def +=(elem: B) = { base += elem; this }
        override def clear() = base.clear()
        override def result() = new MySeq[B](base.result())
      }
    }
    
    object MySeq {
      implicit def canBuildFrom[A <: MyA]: CanBuildFrom[MySeq[_], A, MySeq[A]] = ???
    }
    
    val list = List(new MyA, new MyA, new MyA, new MyA)
    val vect = list.toVector
    val mLst = new MySeq(list)
    val mVec = new MySeq(vect)
    {
      val res = mLst.filter(_.hashCode != list.head.hashCode)
      implicitly[res.type <:< MySeq[MyA]]
    }
    {
      val res = (mVec: Seq[MyA]).map(identity)
      assert(res.isInstanceOf[Vector[_]])
    }
    {
      val res = (mLst: Seq[MyA]).map(identity)
      assert(res.isInstanceOf[List[_]])
    }
    
        2
  •  1
  •   Bruno    7 年前

    canBuildFrom 实施:

    class MyA
    
    class MySeq[+A <: MyA](val s: Seq[A]) 
      extends Seq[A]
      with SeqLike[A, MySeq[A]]
    {
      override def iterator = s.iterator
      override def apply(i: Int) = s(i)
      override def length = s.length
    
      override def toString = s.map(_.toString).mkString("\n")
    
      override def companion = s.companion
      protected[this] override def newBuilder = MySeq.newBuilder
    }
    
    object MySeq {
      def newBuilder[A <: MyA] = new mutable.Builder[A, MySeq[A]] {
        private[this] val base = Seq.newBuilder[A]
        override def +=(elem: A) = { base += elem; this }
        override def clear() = base.clear()
        override def result() = new MySeq[A](base.result())
      }
    
      implicit def canBuildFrom[A <: MyA]: CanBuildFrom[MySeq[_], A, MySeq[A]] = new CanBuildFrom[MySeq[_], A, MySeq[A]] {
        def apply(from: Election[_]) = newBuilder
        def apply() = newBuilder
      }
    }