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

时间:2017-09-14 03:30:24

标签: kotlin

我们说我有一个功能:

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.

如果限制类型&#34;设置&#34;在我的控制下,我可以使用界面或密封类来实现这一目标。 E.g。

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
)

...... I.e。有一组混合的&#34;秒&#34; (Pair)种类。

2 个答案:

答案 0 :(得分:2)

所以快速总结一下:

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

TL; DR:没有某种包装器,你想要实现的目标是不可能的,因为

  1. 我们在Kotlin中没有Sum-Types,所以没办法告诉编译器你期望一个Int或一个Double或一个Float而没有别的
  2. 如果库方法需要某些内容Pair<String, *>,我们就无法告诉编译器,我们只希望能够给它一个String而不是{{1 }}
  3. 获得该行为的一种方法是创建一个装饰器(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>) 你 可以创建Decoractor-Class:

    Foo.doSomething()

    如果没有某种Wrapper,以下示例是不可能的,因为Kotlin中没有Sum-Types:

    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)
    

答案 1 :(得分:0)

Kotlin目前不支持可表示的并集和交集类型(从1.1.x开始)。

This是相关问题。