【问题标题】:Scala 2.8 CanBuildFromScala 2.8 CanBuildFrom
【发布时间】:2009-11-12 10:38:22
【问题描述】:

继我提出的另一个问题 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 绑定到 B(即,它是 B 的一些集合)这一事实由编译器。类型参数看起来独立于上面的签名和特征 CanBuildFrom 本身的签名:

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

Scala 编译器如何确保That 不会被强制 变成没有意义的东西?

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

编译器如何确定哪些隐式 CanBuildFrom 对象在调用范围内?

【问题讨论】:

标签: generics scala scala-2.8


【解决方案1】:

请注意,map 的第二个参数是一个隐式参数。 必须具有适当类型的隐式作用域,否则,您必须传递这样的参数。

在您的示例中,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

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

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

那么,除了这些自动导入以及您进行的显式导入之外,还能在哪里找到隐式导入?一个地方:应用该方法的实例的伴随对象。

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

无论如何,看看伴随对象的内部。

【讨论】:

  • Daniel - 我怎么知道implicit 对象在我的代码中给定点的范围内?这就是问题归结为,我意识到。它在哪里指定?另外,这个问题与breakOut无关。
  • 除了对象 scala.Predef 中的隐式转换之外,您必须在相同或封闭范围内定义隐式转换,或者您必须显式导入该隐式。
  • “当你从包中导入东西时,唯一可能的隐含是单例” Scala 2.8 包对象仍然如此吗?它们也可以包含隐含的 def 和 val。
  • @JPP 包对象既不是包也不是对象——它们是包对象。对象规则适用于他们。
  • 我的意思是,如果你写了import scala._,你将导入包scala中定义的所有类和特征,以及scala包对象中的所有内容,其中可能包含隐式vals和defs(或者我错了吗?)。当然,scala 包是预先导入的,这只是一个示例。
【解决方案2】:
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]
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-25
    • 2010-12-15
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    • 2011-03-17
    相关资源
    最近更新 更多