Scala编译器如何使用`<:<`来合成隐式证据? [英] How does the Scala compiler synthesize implicit evidence with `<:<`?

查看:95
本文介绍了Scala编译器如何使用`<:<`来合成隐式证据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出Scala中这个(公认的)代码片段:

Given this (admittedly contrived) code fragment in Scala:

object Main extends App {

  class X { def foo = 1 }

  def f[A](value: A)(implicit ev: A <:< X) = { value.foo }

  println(f(new X()))

}

Scala编译器如何进行此传递?我已经看过Predef中的一些代码,但是我不理解其实现.请提供详细的逐步说明.

What does the Scala compiler do to make this pass? I have looked at some code in Predef but I don't understand the implementation. Please give a detailed step by step explanation.

推荐答案

呼叫站点

让我们看看在编写时类型推断器的作用:

Callsite

Let's look at what the type inferencer does when you write:

f(new X())

首先必须弄清楚f的模板参数A是什么. Scala中的类型推断在参数列表中从左到右,因此(对于new X类型为X),我们得到

It first has to figure out, what the template parameter A of f is. Type inference in Scala goes left to right in argument lists, so trivially (given new X is of type X), we get

f[X](new X)

现在,编译器需要找到类型为X <:< X的隐式值(请记住,A已解析为X).

Now the compiler needs to find an implicit value of type X <:< X (remember, A got resolved to X).

要查找隐式值,编译器会在各个地方(其中包括您当前的作用域(在其中导入了Predef._的地方))进行查找.

To find implicit values, the compiler looks in various places, amongst others your current scope (in which Predef._ is imported).

然后,编译器会找到 Predef.$conforms :

The compiler then finds Predef.$conforms:

implicit def $conforms[A]: A <:< A = // some implementation

因此,可以通过使用X作为参数来调用它来生成X <:< X:

So this can be used to produce a X <:< X, by invoking it with X as parameter:

f[X](new X)(Predef.$conforms[X])

$conforms的实际实现对于类型检查器而言无关紧要.

The actual implementation of $conforms does not matter as far as the type checker is concerned.

现在让我们看一下实现:

Now lets look at the implementation:

 def f[A](value: A)(implicit ev: A <:< X) = { value.foo }

值的类型为A(所以未知).您要在value上调用foo.由于未在A上定义foo,因此编译器正在寻找将A转换为具有foo的隐式函数(或方法).

Value is of type A (so something unknown). You want to call foo on value. Since foo is not defined on A, the compiler is looking for an implicit function (or method) that converts A into something that has a foo.

范围之内是这样的:ev(A <:< BA => B的扩展).

There is such a thing in scope: ev (A <:< B extends A => B).

因此,编译器使用ev插入隐式转换:

Therefore, the compiler inserts an implicit conversion using ev:

ev(value).foo

关于差异的小注释

您可能已经注意到,<:<在其参数中是变体:<:<[-From, +To].这可用于生成实际的子类型证据.考虑:

Small Note About Variance

As you might have noticed, <:< is variant in its parameters: <:<[-From, +To]. This can be used to generate actual subtyping evidences. Consider:

class A
class B extends A

val ev1: A <:< A = conforms
val ev2: B <:< A = ev1 // makes sense, works because of variance

// Also
val ev3: B <:< B = conforms
val ev4: B <:< A = ev3 // makes sense, works because of variance

这就是原因,为什么不需要具有两个类型参数的conforms方法.此外,请注意,=:=明确希望此行为(因为这是类型等效),因此它是不变的.

This is notably the reason, why there is no need for a conforms method with two type parameters. Further, note that this behavior is specifically not wanted for =:= (since this is type equivalence), so it is invariant.

这篇关于Scala编译器如何使用`&lt;:&lt;`来合成隐式证据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆