2010-10-06 53 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