如何在 Scala 中使用有界类型参数创建自定义 Seq?
How to create a custom Seq with bounded type parameter in 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
?
我没有收到第 26 行的错误:
override def companion = MySeq
可能是其他原因造成的。
无论如何,问题是您不能拥有 GenericCompanion[MySeq]
(SeqFactory
的超类型)。原因是 GenericCompanion[Coll]
意味着您可以为任何 A
构造一个 Coll[A]
(参见 newBuilder
的签名)。你也不能有MySeq[A] <: GenericTraversableTemplate[A, MySeq]
,因为genericBuilder
是不可能的。这是有道理的; MySeq
并不是真正的 "generic collection" 因为它希望它的元素都是 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[_]])
}
这是一个完整的 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
}
}
考虑以下工作习惯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
?
我没有收到第 26 行的错误:
override def companion = MySeq
可能是其他原因造成的。
无论如何,问题是您不能拥有 GenericCompanion[MySeq]
(SeqFactory
的超类型)。原因是 GenericCompanion[Coll]
意味着您可以为任何 A
构造一个 Coll[A]
(参见 newBuilder
的签名)。你也不能有MySeq[A] <: GenericTraversableTemplate[A, MySeq]
,因为genericBuilder
是不可能的。这是有道理的; MySeq
并不是真正的 "generic collection" 因为它希望它的元素都是 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[_]])
}
这是一个完整的 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
}
}