Scala:带类型参数的类的隐式证据 [英] Scala: Implicit evidence for class with type parameter
问题描述
这里是一个简单的设置,具有两个特征,一个类的协变量类型参数受以前的特征限制,第二个类的类型参数受另一个类限制.对于这两个类,仅当两个特征之一作为类型参数的基础时,一种特定的方法(通过隐式证据)才可用.这样编译就可以了:
Here is a simple setup with two traits, a class with a covariant type parameter bounded by the previous traits, and a second class with a type parameter bounded by the other class. For both classes, a particular method is available (via implicit evidence) only if one of the two traits underlies the type parameter. This compiles fine:
trait Foo
trait ReadableFoo extends Foo {def field: Int}
case class Bar[+F <: Foo](foo: F) {
def readField(implicit evidence: F <:< ReadableFoo) = foo.field
}
case class Grill[+F <: Foo, +B <: Bar[F]](bar: B) {
def readField(implicit evidence: F <:< ReadableFoo) = bar.readField
}
但是,由于Bar
在F
中是协变的,因此我不需要在Grill
中使用F
参数.我只需要B
是Bar[ReadableFoo]
的子类型.但是,这失败了:
However, since Bar
is covariant in F
, I shouldn't need the F
parameter in Grill
. I should just require that B
is a subtype of Bar[ReadableFoo]
. This, however, fails:
case class Grill[+B <: Bar[_]](bar: B) {
def readField(implicit evidence: B <:< Bar[ReadableFoo]) = bar.readField
}
出现错误:
error: Cannot prove that Any <:< this.ReadableFoo.
def readField(implicit evidence: B <:< Bar[ReadableFoo]) = bar.readField
为什么不考虑隐式证据?
Why is the implicit evidence not being taken into account?
推荐答案
之所以可以调用bar.readField
,是因为证据实例<:<
允许从B
到Bar[ReadableFoo]
的隐式转换.
The call bar.readField
is possible because the evidence instance <:<
allows an implicit conversion from B
to Bar[ReadableFoo]
.
我认为要调用readField
的问题,您需要一个连续的证据参数F <:< ReadableFoo
.因此,我的猜测是,编译器没有在隐式解析的第一个搜索阶段完全替换Bar
的类型参数(因为要找到readField
,因此它只需要任何Bar
).然后它阻塞了第二个隐式分辨率,因为据我所知,没有任何形式的回溯".
The problem I think that to call readField
you need a successive evidence parameter F <:< ReadableFoo
. So my guess is, the compiler doesn't fully substitute the type parameter of Bar
in the first search stage of the implicit resolution (because to find readField
, it just requires any Bar
in the first place). And then it chokes on the second implicit resolution, because there is no form of 'backtracking' as far as I know.
无论如何.好处是,您不仅了解编译器,而且可以使用<:<
的apply
方法或使用辅助方法implicitly
:
Anyway. The good thing is, you know more than the compiler and you can engage the conversion explicitly, either by using the apply
method of <:<
, or by using the helper method implicitly
:
case class Grill[+B <: Bar[_]](bar: B) {
def readField(implicit evidence: B <:< Bar[ReadableFoo]) = evidence(bar).readField
}
case class Grill[+B <: Bar[_]](bar: B) {
def readField(implicit evidence: B <:< Bar[ReadableFoo]) =
implicitly[Bar[ReadableFoo]](bar).readField
}
还有另一种可能是最干净的可能性,因为它不依赖于<:<
的实现,这可能是@Kaito建议的问题:
There is another possibility which might be the cleanest, as it doesn't rely on the implementation of <:<
which might be a problem as @Kaito suggests:
case class Grill[+B <: Bar[_]](bar: B) {
def readField(implicit evidence: B <:< Bar[ReadableFoo]) =
(bar: Bar[ReadableFoo]).readField
}
这篇关于Scala:带类型参数的类的隐式证据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!