在我问了另一个问题Scala 2.8 breakout之后,我想进一步了解有关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)
我不能完全掌握的是由编译器强制将
That
绑定(bind)到B
(即,它是B的某种集合)的事实。类型参数看起来既与上面的签名无关,又与特征CanBuildFrom
本身的签名无关:trait CanBuildFrom[-From, -Elem, +To]
Scala编译器如何确保不能将
That
强制转换为没有意义的内容?> val s: Set[String] = List("Paris", "London").map(_.length) //will not compile
编译器如何确定在调用范围内包含哪些隐式
CanBuildFrom
对象? 最佳答案
请注意,map
的第二个参数是隐式参数。 必须在具有适当类型的范围内是隐式的,否则,您必须传递此类参数。
在您的示例中,That
必须为Set[String]
,B必须为Int
,Repr
必须为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
绑定(bind)了第二个和第三个参数,所以隐式的问题将不起作用。那么,关于这样的隐式,如何知道在哪里寻找呢?首先,Scala确实将一些东西导入了所有范围。现在,我可以回顾以下进口:
import scala.package._ // Package object
import scala.Predef._ // Object
// import scala.LowPriorityImplicits, class inherited by Predef
import scala.runtime._ // Package
由于我们关注隐式,因此请注意,从包中导入内容时,唯一可能的隐式是单例。另一方面,从对象(单例)导入事物时,可以具有隐式定义,值和单例。
现在,
CanBuildFrom
和Predef
内部有LowPriorityImplicits
隐式对象,它们与字符串有关。它们使我们能够编写"this is a string" map (_.toInt)
。因此,除了这些自动导入和您进行的显式导入之外,还可以在哪里找到隐式?一个地方:在其上应用方法的实例的伴随对象。
我说的是伴随对象,是复数形式,因为由所讨论实例的类继承的所有特征和类的伴随对象可能包含相关的隐式对象。我不确定实例本身是否包含隐式实例。老实说,我现在无法重现此内容,因此我肯定在这里犯了某种错误。
无论如何,请查看伴随对象的内部。