首页 文章

Scala 2.8 CanBuildFrom

提问于
浏览
26

继我提出的另一个问题之后,我想更多地了解Scala方法 TraversableLike[A].map ,其签名如下:

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

请注意有关此方法的一些事项:

  • 它需要一个函数将遍历中的每个 A 转换为 B .

  • 它返回 That 并采用类型为 CanBuildFrom[Repr, B, That] 的隐式参数 .

我可以这样称呼如下:

> val s: Set[Int] = List("Paris", "London").map(_.length)
s: Set[Int] Set(5,6)

I cannot quite grasp 是如何将 That 绑定到 B (即,它是B的一些集合)的事实由编译器强制执行 . 类型参数看起来独立于上面的签名和特征 CanBuildFrom 本身的签名:

trait CanBuildFrom[-From, -Elem, +To]

Scala编译器如何确保 That 不能强制进入没有意义的东西?

> val s: Set[String] = List("Paris", "London").map(_.length) //will not compile

编译器如何确定调用范围内的隐式 CanBuildFrom 对象是什么?

2 回答

  • 29

    请注意, map 的第二个参数是隐式参数 . must 是具有适当类型的隐式范围,否则,您 must 传递此类参数 .

    在您的示例中, That 必须为 Set[String] ,B必须为 IntRepr 必须为 List[String] . 因此,要编译它,您需要在作用域中使用以下隐式对象:

    implicit object X: CanBuildFrom[List[String], Int, Set[String]]
    

    范围内没有这样的东西 . 此外, breakOut 无法提供它,因为它本身需要一个隐含的 CanBuildFrom ,其第一个类型可以是任何类( Nothing 的反变体后代),但是受其他类型的限制 .

    例如,从 List 的伴随对象查看 CanBuildFrom 工厂:

    implicit def  canBuildFrom [A] : CanBuildFrom[List, A, List[A]]
    

    因为它通过 A 绑定第二个和第三个参数,所以隐含的问题将不起作用 .

    那么,对于这样的暗示,如何知道在哪里寻找?首先,Scala确实在所有范围中导入了一些内容 . 现在,我可以回想一下以下的进口:

    import scala.package._ // Package object
    import scala.Predef._  // Object
    // import scala.LowPriorityImplicits, class inherited by Predef
    import scala.runtime._ // Package
    

    由于我们关注implicits,请注意当您从包中导入内容时,唯一可能的瑕疵是单例 . 另一方面,当您从对象(单例)导入内容时,您可以拥有隐式定义,值和单例 .

    现在, PredefLowPriorityImplicits 中有 CanBuildFrom 含义,它们与字符串有关 . 它们使我们能够写出 "this is a string" map (_.toInt) .

    那么,除非这些自动导入和你做的显式导入,否则可以隐藏其他地方?一个地方:应用该方法的实例的伴随对象 .

    我说复数形式的伴随对象,因为所讨论的实例的类继承的所有特征和类的伴随对象可能包含相关的含义 . 我现在正在重现这一点,所以我肯定在这里犯了一些错误 .

    无论如何,请查看伴随对象 .

  • 0
    object ArrayBuffer extends SeqFactory[ArrayBuffer] {
      /** $genericCanBuildFromInfo */
      implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ArrayBuffer[A]] = new GenericCanBuildFrom[A]
      def newBuilder[A]: Builder[A, ArrayBuffer[A]] = new ArrayBuffer[A]
    }
    

相关问题