2010-10-06 52 views
9

我在某些情况下使用类型设计API,但是我遇到了隐式解决方案的问题。如下所示,如果存在类型A的隐式对象,但类型B extends A的对象被传递给该方法,则无法找到隐式对象。有没有办法让这个工作或调用者必须将隐式对象放入每个子类的作用域中?在Scala中输入类模式不考虑继承?

下面是一个例子:

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

我也尝试将调用的定义更改为: def call [X,X2 <:X](x:X2) (隐含x2:T [X])= println(x) 而这并没有帮助 – 2010-10-06 06:41:13

回答

2

尝试这种情况:

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

import T._ 

或简单地:

implicit def TA[X <: A] = new T[X] 
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) 
[email protected] 

scala> call(new B) 
[email protected] 

scala> val b = new B 
b: B = [email protected] 

scala> call(b) 
[email protected] 

在你的情况编译失败,因为def call[X:T](x:X) = println(x)作为call: [X](x: X)(implicit evidence$1: T[X])Unit处理。为了传递子类型,可以使用广义类型约束。

+0

有没有一种方法来实际获得证据$ 1?例如,假设T是一个函数,x是参数。我不能称为证据(x) – 2010-10-06 09:33:00

+0

为什么你不能?你可以通过名称'evidence $ 1'来调用它,就像任何其他的[implicit]参数一样。 – 2010-10-06 09:57:07

+0

如果你在方法上有几个类型参数,将会有证据$ 1,证据$ 2等:[X,Z](x:X)(隐式证据$ 1:T [X],隐式证据$ 2:T [Z] )Unit' – 2010-10-06 10:00:39

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]

+0

问题是,即使你也定义了隐式对象TB扩展T [B],隐式[T [B]] == T.TA'。 http://lampsvn.epfl.ch/trac/scala/ticket/2509 – retronym 2010-10-06 22:40:25

+0

听起来很合理,因为TA比TB更具体,TA是TB,因此T [B]应该是可用的。如果你想让隐式精确地匹配类型,定义T为T [X] – IttayD 2010-10-07 04:27:55