Scala:带类型参数的类的隐式证据 [英] Scala: Implicit evidence for class with type parameter

查看:86
本文介绍了Scala:带类型参数的类的隐式证据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里是一个简单的设置,具有两个特征,一个类的协变量类型参数受以前的特征限制,第二个类的类型参数受另一个类限制.对于这两个类,仅当两个特征之一作为类型参数的基础时,一种特定的方法(通过隐式证据)才可用.这样编译就可以了:

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
}

但是,由于BarF中是协变的,因此我不需要在Grill中使用F参数.我只需要BBar[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,是因为证据实例<:<允许从BBar[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屋!

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