2013-09-23 38 views
5

我試圖調用此方法set記錄here,Java庫jOOQ,有簽名:Scala爲什麼不在這裏使用隱式轉換?

<T> ... set(Field<T> field, T value) 

這斯卡拉線是一個問題:

.set(table.MODIFIED_BY, userId) 

MODIFIED_BY是代表一個Field<Integer>表列。 userIdIntPredef有一個從IntInteger的隱式轉換,所以爲什麼不使用它?我得到這個:

type mismatch; found: org.jooq.TableField[gen.tables.records.DocRecord,Integer]  
      required: org.jooq.Field[Any] 
Note: Integer <: Any 
(and org.jooq.TableField[gen.tables.records.DocRecord,Integer] <: 
    org.jooq.Field[Integer]), but Java-defined trait Field is invariant in type T. 
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10) 

更新 - 關於維尼修斯的實例

而不是試圖在註釋中解釋這一點,這裏是一個示範,有沒有當您使用類型與協變被稱爲隱式轉換參數,如List[+T]。比方說,我把這個代碼放在一個文件,編譯並運行它...

case class Foo(str: String) 

object StackOver1 extends App { 

    implicit def str2Foo(s: String): Foo = { 
    println("In str2Foo.") 
    new Foo(s) 
    } 

    def test[T](xs: List[T], x: T): List[T] = { 
    println("test " + x.getClass) 
    xs 
    } 

    val foo1 = new Foo("foo1") 
    test(List(foo1), "abc") 
} 

你會看到,它調用的測試,但從來沒有從String「ABC」到Foo隱式轉換。取而代之的是選擇T,test[T],這是StringFoo之間的常見基類。當您使用IntInteger時,它會選擇Any,但這很令人困惑,因爲列表中Int的運行時表示形式爲Integer。所以它看起來像使用了隱式轉換,但它沒有。您可以通過打開斯卡拉提示驗證...

scala> :type StackOver1.test(List(new java.lang.Integer(1)), 2) 
List[Any] 

回答

2

我什麼都不知道aboutjOOQ,但我認爲這個問題是斯卡拉不理解Java泛型非常好。嘗試:

scala> def test[T](a : java.util.ArrayList[T], b: T) = { println(a,b) } 
scala> val a = new java.util.ArrayList[Integer]() 
scala> val b = 12 
scala> test(a,b) 
<console>:11: error: type mismatch; 
found : java.util.ArrayList[Integer] 
required: java.util.ArrayList[Any] 
Note: Integer <: Any, but Java-defined class ArrayList is invariant in type E. 
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10) 
       test(a,b) 

聽起來很耳熟?

並修復,只需通知類型T調用該方法:test[Integer](a,b)工作正常。

編輯:

還有這裏涉及到的幾件事情:

  1. 擦除 - >當編譯通用的類型將被擦除消失。編譯器將使用Scala的Object,將其視爲Any。然而,ArrayList [Integer]不是ArrayList [Any],即使Integer是任何。 TableField [gen.tables.records.DocRecord,Integer]不是一個Field [Any]。

  2. 類型推理機制 - >它會弄清楚T應該是什麼類型,並且要使用傳入類型(在我們的例子中是第一個共同祖先)的相交支配者。在我們上面的示例中,這將導致使用Any。

  3. 隱式轉換 - >這是最後一步,如果某種類型被轉換爲另一種類型,將被調用,但由於參數的類型被確定爲第一個共同的祖先,所以沒有必要轉換,我們將永遠不會有一個隱式轉換,如果我們不強迫型T.

一個例子來說明的共同祖先是如何來確定T:

scala> def test[T](a: T, b: T): T = a 
scala> class Foo 
scala> class Boo extends Foo 
scala> test(new Boo,new Foo) 
res2: Foo = [email protected] 
scala> test(new Boo,new Boo) 
res3: Boo = [email protected] 
scala> class Coo extends Foo 
scala> test(new Boo,new Coo) 
res4: Foo = [email protected] 
scala> test(new Boo,"qsasad") 
res5: Object = [email protected] 

總結,隱式方法不會被調用,因爲類型推斷機制,在獲取參數之前確定類型,並且由於它使用共同的祖先,所以不需要隱式轉換。

您的代碼產生一個錯誤,由於刪除機制,用這將是重要的,以確定正確的參數類型的類型信息消失。

@RobN,感謝質疑我的回答,我學到了很多與過程。

+0

好吧,謝謝。我的確瞭解List和ArrayList之間的差異,但不幸的是在這種情況下添加[Integer]並不好。它會發生太多,並使代碼變得醜陋。我想知道爲什麼不使用隱式。 –

+0

我會接受這個答案,如果我能找到的文檔或語言規範,說爲什麼不考慮隱含的東西。也許所有類型參數都是在考慮隱含之前決定的。如果不是這種情況,它可以使用'ArrayList [Integer]'而不是'ArrayList [Any]'。你的例子並不完全正確......它不會「強制隱式轉換」。這是因爲Scala是在運行時使用了'Integer'爲它的'Int',但你的測試功能簡單地得到一個'列表[任何]'混淆在這種情況下。沒有隱式轉換函數被調用。 –

+0

@RobN,請幫我改進你的答案。讓我們看看我能否說清楚。第一個例子重現你的錯誤。編譯器完全不認識如何(javageneric,智力)配成(javageneric ,T)。 Scala中的第二個顯示了隱式轉換的發生,注意到b轉換爲java.lang.Integer。我不知道這是在文件中,我只是通過實驗向你展示。如果你有一個可以證明我錯誤的例子,請做。 –

相關問題