CanBuildFrom 如何知道一个类型是否可以从另一个类型构建?

2023-11-24

我读了官方文档但我仍然无法理解它是如何工作的。例如:

class A {
  type Self
}
def seqToSet[T <: A](seq: Seq[T])
                    (implicit cbf: CanBuildFrom[Seq[T], T#Self, Set[T]]) {}

上面的代码可以编译...但是如何编译呢? Scala 如何知道Set可以从一个构建Seq?以及如何确保T#Self(实际上是任何类型)可以放入Set[T]?


一般情况下它不知道。你应该提供这样的CanBuildFrom.

对于像这样的简单情况,你可以使用breakOut:

class A1 extends A { type Self = A1 }
seqToSet(new A1 :: Nil)(collection.breakOut)
// compiles fine

对于更复杂的情况:

case class A2(val i: Int) extends A {
  type Self = Int
}

implicit val A2cbf = new CanBuildFrom[Seq[A2],A2#Self,Set[A2]] {
  import scala.collection.mutable.Builder
  class A2Builder extends Builder[A2#Self,Set[A2]] {
    var es = List[A2]()
    def +=(elem: A2#Self): this.type = { es ::= A2(elem); this }
    def clear(): Unit = es = Nil
    def result(): Set[A2] = es.toSet
  }
  def apply() = new A2Builder
  def apply(from: Seq[A2]) = apply()
}

seqToSet(new A2 :: Nil)(collection.breakOut)
// compiles fine

您应该提供Builder (using CanBuildFrom)这样它就接受A2#Self在方法中+=并返回Set[A2]结果。在代码示例中它创建了新的A2 using elem: A2(elem).

让我们使用几乎相同的参数创建更有用的方法:

def seqToSet[T <: A](seq: Seq[T])(f: T => T#Self)
                    (implicit cbf: CanBuildFrom[Seq[T], T#Self, Set[T]]) = {
  seq.map{f}: Set[T]
}

seqToSet(A2(1) :: A2(2) :: Nil){ a2 => a2.i + 1 }
// Set[A2] = Set(A2(3), A2(2))

这个方法提供了一些奇怪的转换A随着集合类型的转变。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CanBuildFrom 如何知道一个类型是否可以从另一个类型构建? 的相关文章

随机推荐