Kotlin按参数类型调用重载函数(仅已知接口类型时)

时间:2019-11-08 12:47:18

标签: kotlin

我们的代码库具有许多实现的接口。这些被序列化,存储和反序列化。反序列化时,我们调用一个采用接口类型的函数,然后该函数具有一个基于特定类型(即

)分支的巨型when子句。
   when (t) {
      is SubType1 -> ...
      is SubType2 -> ...
      is SubType44 -> ...
   }

这很麻烦,并增加了功能的复杂性。一种可能性是将我们要执行的动作移至实际的实现本身,因此我们可以仅调用t.doAction()并消除when子句。没关系,但是这种特定的逻辑实际上并不属于实现(出于某种原因),因此最好能够调用参数类型的重载函数,并让kotlin根据实现类型确定要调用的类型。不幸的是,它似乎无法做到。我们得到“以下任何函数都不能使用提供的参数来调用。”

这里是否存在一种可以使编译器满意的模式?

以下为人为的示例。 i1是一个底层的Int,但是编译器无法看到它,因为它被键入为接口,即Number。

    fun test() {
        val e = Example()

        val i1 = 123 as Number
        val i2 = 123.0

        e.sqrt(i1)
        e.sqrt(i2)
    }

    class Example {

        fun sqrt(i: Int) {

        }

        fun sqrt(i: Double) {

        }
   }
}

1 个答案:

答案 0 :(得分:0)

您可以创建一个Disionion地图。该功能将与新的实现保持不变,只有地图会变得更大:

val map : Map<KClass<*>, (Any) -> Unit> = mapOf(
  SubType1::class to { /*SubType1 implementation*/ },
  SubType2::class to { /*SubType2 implementation*/ },
  ...
)

fun <T> execute(item: T) {

  map[item::class]?.invoke(item) ?: error("Case not implemented")

}

如果每种情况下都有很多实现行,并且/或者要进行优雅的测试,则可以为每种情况创建一个类,然后分别进行测试:

interface ClassDesicion<T> {
   fun execute(item: T) : Unit
}

val map : Map<KClass<*>, ClassDesicion<*>> = mapOf(
  SubType1::class to SubType1Implementation(),
  SubType2::class to SubType2Implementation(),
  ...
)