2017-02-16 49 views
1

假設我有一個泛型函數:如何禁止某個參數類型的某個子類型的函數調用?

fun <T: Foo> bar(t: T) { ... } 

然後,後來在某個時間點,我決定,這是沒有意義的(甚至是錯誤的)來調用bar(...)T專門爲Qux,這是當然的, ,其中一個Foo的亞型。但是我有很強的理由不改變類的層次結構(例如,我沒有訪問該代碼)。

有沒有辦法禁止撥打bar(t)T專門爲Qux

回答

3

有一種方法可以禁止某個泛型類型參數的調用:棄用。在這種情況下使用@Deprecated註釋看起來非常笨拙,但它解決了問題(*)。

您可以用更具體的類型定義bar(...)過載,並與DeprecationLevel.ERROR水平棄用過載:

@Deprecated("bar should not be called with Qux", level = DeprecationLevel.ERROR) 
fun <T : Qux> bar(t: T) = bar(t as Foo) 

之後,當bar(...)調用了Qux論證解決,棄用過載將採取優先級,因爲它具有更多的具體類型。因此,調用將產生一個編譯時錯誤:

bar(Qux()) 
^ Using 'bar(T): Unit' is an error. bar should not be called with Qux 

(*),但是注意的是,這隻會爲Qux靜態類型(用於呼叫分辨率的)工作,並且功能仍然可以稱爲bar(Qux() as Foo)。相當可觀的是,如果只在運行時知道參數類型,則不能產生編譯時錯誤。


同樣的方法也可以用於生產功能應該以某種方式對null唯一的反應,錯誤或警告,這樣稱他們有沒有空型是沒有意義的:

fun checkNotNull(x: Any?) = x ?: throw IllegalStateException("Should not be null") 

@Deprecated("It is meaningless with a not-null argument.", DeprecationLevel.WARNING) 
@JvmName("checkNotNull--notNullArgument") 
fun checkNotNull(x: Any) = checkNotNull(x as Any?) 
相關問題