11

在某些情况下,我正在使用类型类设计 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:错误:找不到 this.T[this.B] 类型的证据参数的隐式值
呼叫(新B)
    ^
/private/tmp/tc.scala:28:错误:找不到 this.T[this.B] 类型的证据参数的隐式值
呼叫(b)
4

3 回答 3

8

该调用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] 的子类型

于 2010-10-06T12:09:45.433 回答
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. 为了传递子类型,您可以使用广义类型约束。

于 2010-10-06T07:01:10.733 回答
2

尝试这个:

object T {
  implicit def TA[X <: A] = new T[X]
}

import T._

或者简单地说:

implicit def TA[X <: A] = new T[X]
于 2010-10-06T06:58:36.727 回答