Scala编译器如何使用`<:<`来合成隐式证据? [英] How does the Scala compiler synthesize implicit evidence with `<:<`?
问题描述
给出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 <:< B
是A => 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编译器如何使用`<:<`来合成隐式证据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!