2017-10-20 130 views
3

我偶然發現了一個問題,即編譯「不能以下候選人中選擇」時,我指的是rng.max其中rng:IntRange微分曖昧擴展在科特林

inline val <T:Comparable<T>> ClosedRange<T>.max get() = endInclusive // max of range 
inline val <T:Comparable<T>> Iterable<T>.max get():T? = max() // max element 

我想這是因爲IntRange同時實現ClosedRange和(間接通過IntProgressionIterable

如果我想寫一個單個擴展功能將適用於所有的IntRangeLongRangeCharRange(可能但不一定通過擴展ClosedRange),在那裏我可以添加任何語法,將明確解析ClosedRange而不是類似命名Iterable擴展在這種情況下?

回答

3

是否有任何可以明確解析爲ClosedRange的語法,而不是在這種情況下使用類似名稱的Iterable擴展?

您的示例中的客戶端必須與兩個不明確的擴展名區分。

簡單地告訴你要使用哪種類型的編譯器:

val intRange = 0..10 
(intRange as ClosedRange<Int>).max 
1

考慮下面的代碼:

fun Any.someExtensionFunction() = "Any" 
fun String.someExtensionFunction() = "String" 

fun main(args: Array<String>) { 

    val s = "xyz" // type String inferred 

    println(s.someExtensionFunction()) 
    println((s as Any).someExtensionFunction()) 
    println((s as String).someExtensionFunction()) 
} 

輸出:

字符串
任何
字符串

正如你看到的,編譯器會一直呼籲的最低類型擴展功能的繼承結構,除非明確地告訴別人,否則。

所以,s1m0nw1的答案是正確的。

1

如果你想確保ClosedRange吸氣總是被調用,您可以添加一個檢查到Iterable吸氣。由於它內聯的額外的檢查可能會被優化掉:

inline val <T:Comparable<T>> Iterable<T>.max get():T? = when(this) { 
    is ClosedRange<*> -> endInclusive //Specific overload for ClosedRange 
    else -> max() 
}