下面的代码段摘自this ScalaZ教程。
在评估代码示例底部的10.truthy
时,我无法弄清楚如何应用隐式解析规则。
我认为 - 我明白的事情如下:
1)隐式值intCanTruthy
是CanTruthy[A]
的匿名子类的实例,它根据以下内容定义truthys
的{{1}}方法:
Int
2)scala> implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({
case 0 => false
case _ => true
})
intCanTruthy: CanTruthy[Int] = CanTruthy$$anon$1@71780051
隐式转换方法在评估toCanIsTruthyOps
时属于范围,因此当编译器发现10.truthy
没有{时,编译器将尝试使用此隐式转换方法{1}}方法。因此,编译器将尝试寻找一些隐式转换方法,该方法将Int
转换为具有truthy
方法的对象,因此它将尝试10
进行此转换。
3)我怀疑当编译器在truthy
上尝试toCanIsTruthyOps
隐式转换时,可能会以某种方式使用隐式值intCanTruthy
。
但这是我真正迷失的地方。我只是没有看到隐含的解决方法过程如何进行。接下来发生什么 ?怎么样,为什么?
换句话说,我不知道什么是隐式解析序列,它允许编译器在评估toCanIsTruthyOps
时找到10
方法的实现。
问题:
如何将truthy
转换为具有正确10.truthy
方法的某个对象?
那个对象是什么?
该对象来自哪里?
有人可以解释,详细,评估10
时隐式解决方案是如何进行的?
truthy
中的self-type 10.truthy
如何在隐式解决过程中发挥作用?
{ self => ...
在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
答案 0 :(得分:5)
首先,感谢您粘贴一个完全独立的示例。
如何将
10
转换为具有正确truthy
方法的某个对象?
在类型A
不提供该方法的值上调用方法时,必须启动隐式转换,即必须在带有签名的范围内有方法或函数{ {1}} 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]
时如何进行隐式解决吗?
见上面第一个问题的答案。或者作为显式代码:
10.truthy
type A = Int val v: A = 10 val ev: CanTruthy[A] = intCanTruthy val ops: CanTruthyOps[A] = ToCanIsTruthyOps.toCanIsTruthyOps(v)(ev) ops.truthy
中的自我类型{ self => ...
如何在隐式解决过程中发挥作用?
它与隐式解决方案无关。实际上,在您CanTruthy
的示例中,trait CanTruthy
充当self
的别名,甚至没有使用,因此您可以将其删除。
答案 1 :(得分:3)
将A
转换为具有CanTruthyOps[T]
方法的truthy
的方法的签名是:
implicit def toCanIsTruthyOps[A](v: A)(implicit ev: CanTruthy[A])
这意味着它不会仅转换任何A
,而只会转换定义了CanTruthy[A]
的{{1}},这是implicit ev
参数的含义。这意味着,作为将10
映射到具有.truthy
方法的内容的过程的一部分,在包装完成之前也会查找intCanTruthy
。因此,当10
被隐式转换为具有truthy
方法的内容时,intCanTruthy
实例将已被查找并存储为F
属性CanTruthyOps
:
implicit def F: CanTruthy[A] = ev
(实际上我不知道为什么那里需要implicit
; truthy()
会明确转向F
。
F.truthys(self)
至于隐式解决方案的工作原理,您最好查找详细描述该流程的文档。