2017-09-09 63 views
4

考虑以下自定义Seq工作:如何在Scala中创建具有有界类型参数的自定义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的类型参数中,但随后出现其他错误消息。

如何创建一个自定义Seq并绑定了一个类型参数?

+1

你而扩展集合然后在包装类与上限要求封装它的任何理由? –

+0

原因是它会更优雅。我会在这堂课上使用'map'和'filter',每次手动解包和重新包装都会很不方便。 – Bruno

回答

2

我没有收到上线26的错误:

override def companion = MySeq 

也许别的东西造成这一点。

无论如何,问题是你不能有GenericCompanion[MySeq](超类型SeqFactory)。原因是GenericCompanion[Coll]意味着您可以为任何A构建Coll[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是什么(再次,在运行时;编译时将只看到一个Seq)。不过,你可以保留extends SetLike

然后,您需要提供自定义CanBuildFromMySeq.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[_]]) 
} 
0

这是基于HTNW的上述接受的答案全MWE,与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 
    } 
} 
相关问题