我们能否为我们无法控制的类型的联合实现编译时类型安全性?

假设我有一个功能:

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

这种方法的问题是它允许任何类型的对后半部分(例如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 } 

然而,如果我不能控制这些类型,或者它们是原始的,我怎样才能阻止所有事情的发生?

我知道我可以使用smart-cast来获得运行时安全性,但是这可以在编译时完成吗?

或者这种语言不允许吗?

编辑1

我知道我可以创建自己的盒子类型(例如MyBoolean ),并使用一个通用的接口或密封类,但是这将是每个人每次需要时都要编写的样板文件。

编辑2

要清楚,我想能够这样调用:

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

…也就是说,有一组混合的“第二”( Pair )类型。

所以快速总结一下:

你想从库中调用方法,期望Pair<String, *> ,但限制*可能的值。

TL; DR:如果没有某种包装,你试图完成的事情是不可能的,因为

  1. 我们没有Kotlin中的Sum-Types,所以没有办法告诉编译器你期望一个Int或者Double或者Float而没有别的
  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:

 class FooDecorator { val foo = Foo() fun doSomething(param: Pair<String, Int>) { } } 

而下面的例子是不可能没有某种包装,因为在Kotlin中没有和类型:

 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() ) 

Kotlin目前不支持可指定的联合和交集类型(从1.1.x开始)。

这是相关的问题。