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

标签 scala

我读了 official doc但我仍然无法理解它是如何工作的。例如:

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 (使用 CanBuildFrom )这样它就接受 A2#Self在方法中 +=并返回 Set[A2]结果。在代码示例中,它创建了新的 A2使用 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的一些奇怪的转换。随着集合类型的转换。

关于scala - CanBuildFrom 如何知道一个类型是否可以从另一个类型构建?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20762449/

相关文章:

scala - Spark 单元测试失败,错误代码为 "ExceptionInInitializerError",最新版本为 "json4s-jackson"

Scala/Akka/Guice 动态注入(inject) child Actor

java - scala如何隐式使抽象方法有效参数,以便我可以在java中使用方法

java - 对自定义类 arraybuffer 进行排序并获取 scala 中的子集

spring - @Autowired 在 Scala 类的构造函数上

java - 除了 Scala 之外,在 JVM 上运行的替代多线程优化语言?

arrays - Scala 嵌套数组展平

java - 使用Spark API如何处理大型目录树?

scala - 将 Scala 列表拆分为 n 个交错列表

scala - 将 scala 应用程序部署为 docker 容器