Kotlin功能策略模式不编译

时间:2018-02-15 11:40:54

标签: functional-programming kotlin

我正在尝试将几个函数放在地图中。我的想法是:Map<String, [function]>

代码如下:

class UserIdQueriesHandler {

    val strategy: Map<String, KFunction2<@ParameterName(name = "id") String, @ParameterName(name = "options") Array<Options>, Answer>> =
        mapOf( // the compiler complains here
            "d" to ::debt,
            "p" to ::currentProduct
        )

    fun debt(id: String, options: Array<DebtOptions>): UserDebt = UserDebt(isPresent = true, amount = 0.0)

    fun currentProduct(id: String, options: Array<CurrentProductOptions>): UserProducts = UserProducts(products = emptyList())
}

enum class DebtOptions : Options { BOOL, AMOUNT }

enum class CurrentProductOptions : Options { ALL, PRINT, DIGITAL, ENG, HEB, TM }

data class UserDebt(val isPresent: Boolean, val amount: Double) : Answer
data class UserProducts(val products: List<Int>): Answer

AnswerOptions是简单的kotlin接口:

interface Answer
interface Options

编译器输出:

Type inference failed. Expected type mismatch: 
required:
Map<String, KFunction2<@ParameterName String, @ParameterName Array<Options>, Answer>>
found:
Map<String, KFunction2<@ParameterName String, {[@kotlin.ParameterName] Array  & [@kotlin.ParameterName] Array }, Answer>>

2 个答案:

答案 0 :(得分:1)

strategy的类型表示您放入其中的函数可以接受任何Array<Options>作为第二个参数,debtcurrentProduct可以&#t}}。

最简单的解决方法是将其参数类型更改为Array<Options>(或List<Options>;它们可能不需要改变它!)并在运行时失败,如果传递了错误的选项或忽略它们。

文档中的

Variance部分也是相关的。

答案 1 :(得分:1)

由于Array可以同时读写,因此其类型参数为invariant。这使得您无法将Array<DebtOptions>分配给类型为Array<Options>的变量。前者不是后者的子类型,因为它允许您将其他元素放在数组中Options,而不是DebtOptions,从而导致代码中出现问题此数组为Array<DebtOptions>

如果可以,解决方案是让您的函数接受Array<Options>

val strategy: Map<String, KFunction2<String, Array<Options>, Answer>> =
        mapOf(
                "d" to ::debt,
                "p" to ::currentProduct
        )

fun debt(id: String, options: Array<Options>): UserDebt = ...

fun currentProduct(id: String, options: Array<Options>): UserProducts = ...

您可以将此与使用更好的功能类型而不是KFunction2

结合使用
val strategy: Map<String, (String, Array<Options>) -> Answer> = ...