下面的代码片段取自 this ScalaZ 教程。
我无法弄清楚在代码示例底部评估 10.truthy
时如何应用隐式解析规则。
事情 - 我认为 - 我确实理解如下:
1) 隐含值 intCanTruthy
是 CanTruthy[A]
的一个匿名子类的实例,它定义了 truthys
-s 的 Int
方法,根据:
scala> implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({
case 0 => false
case _ => true
})
intCanTruthy: CanTruthy[Int] = CanTruthy$$anon$1@71780051
2)
toCanIsTruthyOps
隐式转换方法在对 10.truthy
求值时在作用域内,所以编译器看到 Int
没有 truthy
方法时,会尝试使用这种隐式转换方法。因此,编译器将尝试寻找一些隐式转换方法,将 10
转换为具有 truthy
方法的对象,因此它将尝试将 toCanIsTruthyOps
转换为该转换。3)我怀疑当编译器在
intCanTruthy
上尝试 toCanIsTruthyOps
隐式转换时,可能会以某种方式使用隐式值 10
。但这是我真正迷失的地方。在此之后,我只是看不到隐式解析过程是如何进行的。接下来发生什么 ?如何以及为什么?
换句话说,我不知道什么是隐式解析序列,它允许编译器在评估
truthy
时找到 10.truthy
方法的实现。问题 :
如何将
10
转换为某些具有正确 truthy
方法的对象?那个对象会是什么?
那个物体会从哪里来?
有人可以详细解释 ,在评估
10.truthy
时隐式解析是如何发生的吗?{ self => ...
中的 self-type CanTruthy
如何在隐式解析过程中发挥作用?scala> :paste
// Entering paste mode (ctrl-D to finish)
trait CanTruthy[A] { self =>
/** @return true, if `a` is truthy. */
def truthys(a: A): Boolean
}
object CanTruthy {
def apply[A](implicit ev: CanTruthy[A]): CanTruthy[A] = ev
def truthys[A](f: A => Boolean): CanTruthy[A] = new CanTruthy[A] {
def truthys(a: A): Boolean = f(a)
}
}
trait CanTruthyOps[A] {
def self: A
implicit def F: CanTruthy[A]
final def truthy: Boolean = F.truthys(self)
}
object ToCanIsTruthyOps {
implicit def toCanIsTruthyOps[A](v: A)(implicit ev: CanTruthy[A]) =
new CanTruthyOps[A] {
def self = v
implicit def F: CanTruthy[A] = ev
}
}
// Exiting paste mode, now interpreting.
defined trait CanTruthy
defined module CanTruthy
defined trait CanTruthyOps
defined module ToCanIsTruthyOps
在
10
上尝试类型类:scala> import ToCanIsTruthyOps._
import ToCanIsTruthyOps._
scala> implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({
case 0 => false
case _ => true
})
intCanTruthy: CanTruthy[Int] = CanTruthy$$anon$1@71780051
scala> 10.truthy
res6: Boolean = true
最佳答案
首先,感谢您粘贴一个完全独立的示例。
当在类型 A
不提供该方法的值上调用方法时,必须进行隐式转换,即范围内必须有一个方法或函数,其签名为 A => B
且 B
具有相关方法( truthy
)。在转换方法的情况下,它可能会要求相应地查找额外的隐式参数。
转换方法是 toCanIsTruthyOps
,通过导入 ToCanIsTruthyOps
的内容可用。那么上句中的 B
类型就是 CanTruthyOps
,转换方法就是 toCanIsTruthyOps
。只要找到隐式类型类证据参数 CanTruthy
就可以被编译器调用。因此,由于 type A = Int
,如果调用 CanTruthy[Int]
将成功,编译器必须找到 10.truthy
类型的隐式值。
它在几个地方寻找这样的值。它可能在 Int
的伴随对象(不存在)或 CanTruthy
的伴随对象中,或者它被明确导入到当前作用域中。这里使用最后一种情况。您显式创建了隐式值 intCanTruthy
,现在已找到该值。就是这样。
将有一个 CanTruthyOps
的临时实例,其目的仅仅是在证据类型类值上调用 truthys
(此处为您的 intCanTruthy
)。
它可以在隐式转换 Int => CanTruthyOps[Int]
的查找中找到。转换执行该对象的实例化。
请参阅上面第一个问题的答案。或者作为显式代码:
type A = Int
val v: A = 10
val ev: CanTruthy[A] = intCanTruthy
val ops: CanTruthyOps[A] = ToCanIsTruthyOps.toCanIsTruthyOps(v)(ev)
ops.truthy
它与隐式解析无关。实际上,在您的
trait CanTruthy
示例中, self
充当 this
的别名,甚至没有使用,因此您可以将其删除。关于scala - 这个 "simple"ScalaZ 教程代码示例中的隐式解析序列是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26698313/