【问题标题】:How to create a custom Seq with bounded type parameter in Scala?如何在 Scala 中创建具有有界类型参数的自定义 Seq?
【发布时间】:2018-02-18 03:59:17
【问题描述】:

考虑以下工作自定义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,绑定类型参数?

【问题讨论】:

  • 您扩展集合而不是将其封装在具有上限要求的包装类中的任何原因?
  • 原因是它会更优雅。我会在这个类上大量使用mapfilter,每次手动解包重新打包会很不方便。

标签: scala collections types factory


【解决方案1】:

我没有收到第 26 行的错误:

override def companion = MySeq

也许是其他原因造成的。

无论如何,问题在于您不能拥有GenericCompanion[MySeq]SeqFactory 的超类型)。原因是GenericCompanion[Coll] 意味着您可以为任何A 构造一个Coll[A](参见newBuilder 的签名)。你也不能拥有MySeq[A] &lt;: GenericTraversableTemplate[A, MySeq],因为genericBuilder 是不可能的。这是有道理的; MySeq 并不是真正的“通用集合”,因为它希望它的元素都是 MyA

解决方案是拥有MySeq[B] &lt;: 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 &lt;: 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】:

    这是一个完整的 MWE,基于上面 HTNW 接受的答案,实现了 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
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-17
      • 2019-01-02
      • 1970-01-01
      • 1970-01-01
      • 2015-09-14
      • 1970-01-01
      • 1970-01-01
      • 2021-06-16
      • 2010-10-25
      相关资源
      最近更新 更多