2017-09-14 69 views
2

比方說,我有一個函數:我們能否爲我們無法控制的類型聯合實現編譯時類型安全性?

fun doSomething(vararg pairs: Pair<String, *>) { 
    // Do things with the pairs 
} 

這種方法的問題是,它允許任何類型的Pair(例如,Pair<String, CustomType1>)下半場。

如果我只想允許有限數量的類型,我該如何實現?

如果函數有一個簡單的簽名,我可以實現通過超載的限制,像這樣:

fun doSomethingSimpler(param: Boolean) { 
    // Boolean implementation 
} 

fun doSomethingSimpler(param: Int) { 
    // Int implementation 
} 

// etc. 

如果受限鍵入「set」是在我的控制,我可以使用密封接口或類來實現這一點。例如。

sealed class Root 
class Child1 : Root() 
class Child2 : Root() 

fun doSomethingICanControl(param: Root) { 
    // Root implementation 
} 

然而,如果我沒有在控制類型或者他們是原始的,如何防止*從通過允許一切嗎?

我知道我可以使用智能鑄件獲得運行時的安全性,但這種在編譯的時候做什麼?

或者該語言不允許嗎?

編輯1

我知道我可以創建自己的盒子類型(例如MyBoolean),並使用一個通用的接口或密封類,但是這將是樣板,每個人都將不得不每次他們需要時間寫。

編輯2

要清楚,我希望能夠做出像這樣的調用:

doSomething(
    "key1" to false, 
    "key2" to "value2", 
    "key3" to 86 
) 

...即擁有一套混合的「第二」(中Pair)類型。

+0

標記界面是實現這一點的唯一方法。對於您無權訪問的類(例如int),您可以自行將其放入。 – Joshua

+1

自編輯2使我的答案無效。 –

+0

你能再詳細一點嗎? * doSomething *你打電話給圖書館的方法嗎?或者一個庫調用你的* doSomething *? – D3xter

回答

1

於是迅速概括:

你想打電話從預計Pair<String, *>, 文庫的方法,但限制可能值*即可。

TL; DR:你所要完成是不可能沒有某種形式的包裝,因爲

  1. 我們在科特林沒有總和類型,所以沒有辦法告訴你期待一個編譯器詮釋或雙或浮動和沒有別的
  2. 如果一個庫方法期望的東西是Pair<String, *>,我們沒有辦法告訴編譯器,我們只是想能夠給它String而不是*

一種方式來獲得這種行爲是創建一個裝飾(Decorator Pattern),例如創建自己的擴展方法只允許一個子集

class Foo { 
    //Allows everything 
    fun doSomething(param: Pair<String, *>) 
} 

//Now lets create our own extension methods 
fun Foo.doSomethingWithInt(param: Pair<String, Int>) 

fun Foo.doSomethingWithBoolean(param: Pair<String, Boolean>) 

fun Foo.doSomethingWithString(param: Pair<String, String>) 

或者,如果你不希望能夠調用Foo.doSomething()您 可以創建一個Decoractor級:

class FooDecorator { 
    val foo = Foo() 

    fun doSomething(param: Pair<String, Int>) { } 
} 

而下面的例子是不可能沒有某種形式包裝的,因爲沒有總和類型在科特林:

doSomething(
    "key1" to false, 
    "key2" to "value2", 
    "key3" to 86 
) 

你可以做的是一樣的東西:

首先,創建自己的JSONItem類型,並添加擴展的方法作爲一個

class JSONItem<T> private constructor (item: T) 

fun Int.asJSONItem() = JSONItem(this) 

fun String.asJSONItem() = JSONItem(this) 

fun Boolean.asJSONItem() = JSONItem(this) 

然後你可以做這樣的事情,可以用來類型:

//Your own personal doSomething 
fun doSomething(varargs: param: Pair<String, JSONItem>) { 
    //Call the real doSomething() 
    doSomething(param.map { Pair(it.first, it.second.item) }} 
} 

doSomething(
    "key1" to false.asJSONItem(), 
    "key2" to "value2".asJSONItem(), 
    "key3" to 86.asJSONItem() 
) 
+0

您的'Foo'擴展重載不會編譯,因爲您沒有使用不同的JVM名稱對它們進行註釋。至於你的'.asJSONItem()'方法,那還不錯。我只是想知道,這種語言是否可以處理這個問題,而不需要重複樣板,而且它似乎目前不能。 – pleasedesktop

+0

@pleasedesktop哦,是的,你是對的。修復 – D3xter

0

Denotable Kotlin目前不支持聯合和交集類型(從1.1.x開始)。

This是相關問題。

相關問題