gpt4 book ai didi

scala - 如何在 Scala 中创建具有有界类型参数的自定义 Seq?

转载 作者:行者123 更新时间:2023-12-04 20:31:10 24 4
gpt4 key购买 nike

考虑以下工作习惯 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绑定(bind)类型参数?

最佳答案

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

override def companion = MySeq

也许是其他原因造成的。

无论如何,问题是您不能拥有 GenericCompanion[MySeq] ( SeqFactory 的父类(super class)型)。原因是 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是(同样,在运行时;编译时只会看到 Seq )。您可以保留 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[_]])
}

关于scala - 如何在 Scala 中创建具有有界类型参数的自定义 Seq?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46129794/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com