標籤:

Kotlin泛型語法中的歧義性

在Java中,如果我們需要顯式傳遞給泛型方法類型引元,我們需要將需要傳遞的類型引元放置在方法名前的尖括弧對內。例如,對於下面的泛型方法:

class C {n public static <A> void f() {}n}n

我們需要這樣來調用:

C.<String>f();n

這樣的寫法讓很多人感到不符合習慣。而在Kotlin中,我們需要這樣調用:

C.f<String>()n

相比較而言,下面的寫法可能更符合大多數人的習慣。不過相對來說,這樣做也引入了Java泛型語法想要避免的歧義性問題。考慮下面的一段代碼:

class C {nval f: Int = 0n fun <T1, T2> f(i: Int): Int {nreturn in }n}nnfun f(b1: Boolean, b2: Boolean): Unit {nprintln("f(Boolean, Boolean)")n}nnfun f(i: Int): Unit {nprintln("f(Int)")n}nnfun <A, B> test() {nval A = 0n val B = 0nn val a = C()nval c = 0nn f(a.f<A, B>(c))n}nnfun main(args: Array<String>): Unit {ntest<Int, Int>()n}n

這樣的一段代碼會列印出什麼呢?對於這裡來說,很明顯能看出會列印"f(Int)"。但是實際上,這個結論並沒有這麼明顯。我們稍微把對於f的調用變換一下形式,加入幾個空格,從

f(a.f<A, B>(c))n

改為

f(a.f < A, B > (c))n

我們發現,a.f<A, B>(c)可能是一個泛型方法的調用,也有可能是比較a.f和A,以及B和c。而這種情況正是我們在Java中想要避免的歧義性。

而對於Kotlin編譯器來說,在這種情況下,<>總是會被解析為泛型方法的調用,而不是比較操作符。所以:

f((a.f)< A, B > (c))n

也會被當做獲取a的f屬性,然後試圖調用這個屬性的帶一個泛型參數的invoke方法。甚至這樣

f((a.f)< A, B > c)n

也會被解析為泛型方法調用而出錯

如果我們真的需要列印出"f(Boolean, Boolean)",我們需要用括弧把兩個參數中至少一個括起來:

f(a.f < A, (B > c)) //或者nf((a.f < A), B > c)n

推薦閱讀:

廢文(一)
開源文檔翻譯的質量保障實踐
Kotlin雜談(一) - 高等函數(Curry + 閉包)

TAG:Kotlin |