我在某些情况下使用类型类设计API但是我遇到了隐式解析的问题。如下所示,如果存在类型A的隐式对象,但将类型为B extends A
的对象传递给该方法,则无法找到隐式对象。有没有办法使这项工作或调用者必须将隐式对象放入每个子类的范围?
以下是一个例子:
class A
class B extends A
class T[+X]
object T {
implicit object TA extends T[A]
}
def call[X:T](x:X) = println(x)
// compiles
call(new A)
// doesn't compile
call(new B)
var a = new A
// compiles
call(a)
a = new B
// compiles
call(a)
val b = new B
// doesn't compile
call(b)
使用以下输出无法编译:
/private/tmp/tc.scala:16: error: could not find implicit value for evidence parameter of type this.T[this.B] call(new B) ^ /private/tmp/tc.scala:28: error: could not find implicit value for evidence parameter of type this.T[this.B] call(b)
答案 0 :(得分:7)
调用call(new B)
表示call[B](new B)(tB)
,使得tb属于类型T [B]或其子类。 (期望类型为T的参数的方法只能期望T的T或子类,例如,def foo(s: String)
不能使用类型Any
的参数调用。 T [A]不是T [B]
要修复,您可以将T更改为已定义T[-X]
。这意味着编译器会将T [A]视为T [B]
答案 1 :(得分:4)
以下工作正常:
scala> def call[X](x: X)(implicit evidence: T[X]<:<T[X]) = println(x)
call: [X](x: X)(implicit evidence: <:<[T[X],T[X]])Unit
scala> call(new A)
line0$object$$iw$$iw$A@1d869b2
scala> call(new B)
line2$object$$iw$$iw$B@b3a5d1
scala> val b = new B
b: B = B@30e4a7
scala> call(b)
line2$object$$iw$$iw$B@30e4a7
在您的情况下,编译失败,因为def call[X:T](x:X) = println(x)
被视为call: [X](x: X)(implicit evidence$1: T[X])Unit
。为了传递子类型,您可以使用广义类型约束。
答案 2 :(得分:2)
试试这个:
object T {
implicit def TA[X <: A] = new T[X]
}
import T._
或简单地说:
implicit def TA[X <: A] = new T[X]