大多数时候,当您想确保A <:< B
(或者更正确地说,你想确保A <: B
使用类型证据A <:< B
),这是因为你实际上有一个类型的值A
并希望能够将其视为类型的实例B
.
当你拥有了价值x: A
,通过隐含值的存在证明A
是一个子类型B
不会神奇地改变类型x
to B
.
但出于所有意图和目的<:<
实际上允许这样做,因为它也是一个只返回其参数的函数(它基本上是身份,只是添加了一个稍微隐藏的强制转换)。
这样,当您的方法传递隐式类型值时A <:< B
,你得到的实际上也是一个合适的隐式转换A
to B
(隐式转换x:A
到一个类型的值B
).
如果您实际上不需要转换任何内容,那么这并不重要<:<
延伸Function1
or not.
同样的道理也适用于=:=
.
UPDATE:响应“在 =:= 的情况下,为什么我要将 A 类型的值转换为 A 类型的值?”:
您首先应该注意的是,即使在这种情况下<:<
存在同样明显的矛盾:当然如果A <: B
我可以处理任何类型的值A
作为类型的值B
(这几乎是子类型的定义)。
假设我们有以下通用方法:
class Foo {
def hello() { println("hello!") }
}
def f[T]( value: T )(implicit e: T <:< Foo){
value.hello()
}
class Bar extends Foo
f( new Bar )
编译时f
编译器只知道value
有某种类型T
。
没有任何东西告诉编译器T
永远是一个子类型Foo
。
所以如果不是因为这个事实e: T <:< Foo
还提供了隐式转换T
to Foo
,
然后打电话value.hello()
会失败,因为T
只是编译器不知道的某种类型
任何关于.
只有经过精心设计,才具有隐含的价值e: T <:< Foo
在范围内发生当且仅当T <: Foo
。
但编译器不知道这一点,所以从他的角度来看T
and Foo
是无关的。
因此我们必须为他提供一种转换类型值的方法T
to Foo
,这是由T <:< Foo
证据本身。
正如我所说,同样的理由也适用于=:=
: 有一个实例T =:= Foo
没有向编译器提供有关事实的任何线索
那T = Foo
,因此必须向他提供转换。