在 Kotlin 的 Injekt 库中,如何注入函数而不仅仅是值?

In the Injekt library for Kotlin, how do I inject functions instead of just values?

在Kotlin中使用Injekt库进行依赖注入时:

有时我想注入一个函数,而不是注入一个值。所以像通过以下方式接收函数:

 val function: (Int) -> Int = Injekt.get()

这似乎工作正常,但如果我注册了多个具有相同签名但含义不同的函数,那就不行了。似乎没有办法区分功能。

注: 此题是作者(Self-Answered Questions)特意写下并回答的,所以常用Injekt的地道答案+ Kotlin 主题出现在 SO 中。也欢迎其他答案,还有其他样式的方法!披露,我是 Injekt 库的作者。

你是对的,函数归结为签名的内部表示,例如在这种情况下:

kotlin.jvm.functions.Function1<? super java.lang.Integer, ? extends java.lang.Integer>

并且任何具有相同参数和 return 类型的函数都将具有相同的内部类型并且在 Injekt 中看起来是相同的。以下注册均有效且不冲突:

// register some functions

Injekt.addSingletonFactory {
    val function: (value: Int) -> Int = { value -> value + 1 }
    function
}

Injekt.addSingletonFactory {
    val function: (Long) -> Long = { value -> value - 1 }
    function
}

Injekt.addSingletonFactory {
    val function: (Long) -> String = { value -> "The long is $value" }
    function
}

// inject and use the functions

val intFunction: (Int) -> Int = Injekt.get()
val intResult = intFunction(2)

val longFunction: (Long) -> Long = Injekt.get()
val longResult = longFunction(2)

val longStringFunction: (Long) -> String = Injekt.get()
val stringResult = longStringFunction(10)

如果你想使用相同的函数签名作为不同的含义,你可以为函数的每个含义创建一个class包装器:

class Int1Action(val function: (Int) -> Int) {
    operator fun invoke(i: Int): Int = function(i)
}

加上invoke运算符,自然可以不用引用function成员就可以使用这个wrapper,如:

Injekt.addSingletonFactory {
    val function: (Int) -> Int = { value -> value + 20 }
    Int1Action(function)
}

val action: Int1Action = Injekt.get()
val result = action(2) // call it directly using the invoke operator