下面的代码片段取自 this ScalaZ 教程。

我无法弄清楚在代码示例底部评估 10.truthy 时如何应用隐式解析规则。

事情 - 我认为 - 我确实理解如下:

1) 隐含值 intCanTruthyCanTruthy[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 => BB 具有相关方法( 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/

10-13 02:40