2009-11-12 70 views
26

从另一个问题,我问继,Scala 2.8 breakout,我想了解更多的关于Scala的方法TraversableLike[A].map其签名如下:斯卡拉2.8 CanBuildFrom

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) 

什么我不能很好地领会是怎样的事实That势必B(即,它是B的部分集合)正在被编译器强制执行。该类型的参数看起来是独立的上方和性状CanBuildFrom本身的签名的签名:

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

如何Scala编译器确保That不能被迫到一些东西,没有意义?

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

编译器如何决定什么隐含CanBuildFrom对象范围的电话吗?

+0

这里是后一个相当不错的解释http://blog.bruchez.name/2012/08/getting-to-know-canbuildfrom-without-phd.html – 2012-08-23 21:33:26

+0

为了记录在案,这种用法有概念名称:返回类型多态。 – lcn 2015-03-07 20:18:45

回答

29

请注意,map的第二个参数是一个隐式参数。有必须是一个隐含的范围与适当的类型,否则,你必须通过这样的说法。

在你的榜样,That必须Set[String],B必须IntRepr必须List[String]。因此,对于编译你需要的范围如下隐含对象:

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

有在范围上没有这样的事情。此外,breakOut不能提供它,因为它本身需要一个隐式CanBuildFrom,其第一种类型可以是任何类别(反对后裔Nothing),但受其他类型限制。

看看,例如,在CanBuildFrom工厂从List同伴对象:

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,请注意,当你从包中导入的东西,唯一可能的implicits是单身。另一方面,当你从对象(单例)导入东西时,你可以有隐含的定义,值和单例。

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

因此,除了这些自动导入,以及您制作的显式导入之外,还有哪些地方可以隐式地找到?一个地方:应用该方法的实例的伴随对象。

我说同伴对象s,这是复数形式,因为所讨论的实例的类继承的所有特征和类的伴随对象可能包含相关的含义。我不确定实例本身是否可能包含隐式。说实话,我现在不能复制这个,所以我肯定在这里犯了某种错误。

无论如何,请查看伴侣对象。

+0

丹尼尔 - 我如何知道在我的代码中给定点处隐式对象的范围?我意识到这就是问题归结到的问题。它在哪里指定?另外,这个问题与'breakOut'无关。 – 2009-11-12 13:17:15

+0

除了对象scala.Predef中的隐式转换之外,您必须在相同或封闭范围中定义隐式,否则您必须显式导入该隐式。 – 2009-11-12 15:33:00

+0

“,当你从软件包中导入东西时,唯一可能的情况是单例”对于Scala 2.8软件包对象,情况还是如此吗?它们也可以包含隐式的defs和vals。 – 2011-02-15 14:21:05

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] 
}