4

如果我的名字有關斯卡拉的最討厭的事情,這將是爲下面的代碼:泛型類型和類型參數的Scala類型推斷 - 爲什麼它不起作用?

trait G[+T] 
class H[+T] extends G[T] 

def f[A<:G[X], X<:Int](g :A) 

val g :H[Int] 
f(g) 

編譯器推斷類型F中的最後一次通話[H [INT],沒什麼]和在我面前抱怨自己的愚蠢。

但是知道scala,它實際上比我知道得更清楚。它背後的原因是什麼?由於G和H對於T來說是協變的,所以對於任何類型S來說都是S <: G[X] with H[_] <=> S<: H[X]。這一缺點使我設計了一切,避免明確地指定類型 - 它可能看起來像什麼都沒有,但是當名稱變成'真實'長度和幾乎任何方法都是泛型的,並且通常在兩個泛型類型上工作,事實證明,大多數代碼都是類型聲明。

編輯: 上面的情況是由諾亞解決的,但是當派生類與基類不同,如下所示?

trait G[+X] 
class H[+X, Y] extends G[X] 
class F extends G[Int] 
def f[A<:G[X], X<:Int](g :A) = g 

val h: H[Int, String] = ??? 
val g :F = ??? 
f(g) 
f(h) 

回答

3

如果您A採取型paramater A[_]我認爲你可以得到Scala編譯器同意你的觀點,而不是僅僅將一切都Nothing的:

def f[A[_] <: G[_], X <: Int](g: A[X]) 

作爲一個方面說明,我通常採取每當我遇到類型問題時,都會看到scalaz源代碼,因爲他們通常會遇到它並儘可能地解決問題。

UPDATE

我上面提供的仍然給出的附加約束的工作方法:

trait G[+X] 

    class H[+X, Y] extends G[X] 

    class F extends G[Int] 

    class I extends G[String] 

    def f[A[_] <: G[_], X <: Int](g: A[X]) = g 

    val h: H[Int, String] = new H[Int, String] 
    val g: F = new F 
    val i:I = new I 
    f(g) //works 
    f(h) //works 
    f(i) // should fail and does fail 
+0

謝謝,它有一定的幫助,看起來像在這裏circumvenes問題。但是,如果H是另一種類型,它將無濟於事 - 需要更多的類型參數或沒有,從而實例化G的參數。或者如果H在其參數上引入界限。所以我仍然對如果上述不起作用的理由感興趣。 – Turin

+0

你必須給出另一個不起作用的例子,我敢肯定,你通常可以讓編譯器同意你的看法。上面發生的事情是,編譯器無法從'g:A'中提取類型。它可以發現'A'是'H [Int]',但即使你說'A <:G [X]',你也沒有指定'X',所以它會成爲barf。在我給出的例子中,指定了類型'X',以便編譯器可以推斷它。 – Noah

+0

增加了解釋更實際案例的代碼。 – Turin