【问题标题】:Kotlin is it possible to delegate function or function parameters?Kotlin 是否可以委托函数或函数参数?
【发布时间】:2021-10-12 19:39:40
【问题描述】:

我想拥有例如:

class Foo {
   fun doSomething(arg1: String, arg2: String, arg3: Boolean)
}

class FooDelegate {
   //different fun name
   fun execute by Foo::doSomething
}

反射或其他方式。

我目前拥有的是:

class FooDelegated<R>(
    private val func: KFunction<R>
) {
    fun execute(vararg params: Any) = func.call(*params)
}

这样我就可以打电话了

FooDelegated(Foo::doSomething).execute("1", "2", true)

但是我需要发送不知道的参数。我希望我的编译器知道可以发送哪些参数。否则,我可以编写以下内容,直到运行时才会失败:

   FooDelegated(Foo::doSomething).execute("1", "2", "new argument", false)

请注意,我希望它具有不同的名称,而不是使用接口。

【问题讨论】:

  • fun execute by Foo::doSomething 将如何工作?你甚至没有Foo 的实例!您是否期望execute 采用Foo 的额外参数?
  • 另外,fun execute(arg1: String, arg2: String, arg3: Boolean) = someFoo.doSomething(arg1, arg2, arg3) 有什么问题?
  • 我想不出任何可能的方法在编译时使用注释来做到这一点。反射是无用的,因为它是在运行时完成的。我认为你需要一个定制的 Kotlin 编译器来实现这一点。

标签: kotlin generics parameter-passing kotlin-reflect kotlin-delegate


【解决方案1】:

您可以创建execute 属性并在那里保留函数引用,而不是创建execute() 函数。然后你就可以像使用函数一样使用它了:

class FooDelegate {
    val execute = Foo::doSomething
}

fun main() {
    FooDelegate().execute(Foo(), "hello", "world", true)
}

或者:

class FooDelegate {
    private val foo = Foo()
    val execute = foo::doSomething
}

fun main() {
    FooDelegate().execute("hello", "world", true)
}

您还可以围绕KFunction 创建一个包装器以隐藏其属性,如annotationsisFinal 等,但保留其operator fun invoke 功能。这将使您更灵活地使用这些功能。它还可以用真正的execute() 函数替换execute 属性。但是,您需要为每个属性数量创建一个单独的包装器。它可能看起来像这样:

fun main() {
    delegate(Foo()::doSomething).execute("hello", "world", true)
    delegate(Foo::doSomething).execute(Foo(), "hello", "world", true)
}

fun <P0, P1, P2, R> delegate(func: (P0, P1, P2) -> R) = FunctionDelegate3(func)
fun <P0, P1, P2, P3, R> delegate(func: (P0, P1, P2, P3) -> R) = FunctionDelegate4(func)

class FunctionDelegate3<P0, P1, P2, R>(
    private val func: (P0, P1, P2) -> R
) {
    fun execute(p0: P0, p1: P1, p2: P2): R = func(p0, p1, p2)
}

class FunctionDelegate4<P0, P1, P2, P3, R>(
    private val func: (P0, P1, P2, P3) -> R
) {
    fun execute(p0: P0, p1: P1, p2: P2, p3: P3): R = func(p0, p1, p2, p3)
}

不过,这听起来是一件很奇怪的事情。就像你试图在另一种编程语言中创建编程语言一样。

【讨论】:

  • 嗯,我明白,但它不能按我的需要工作。我真正期待的是发送 Foo:doSomething 作为参数,以便 Delegate 可以使用 execute 调用任何其他定义为参数的函数。我尝试在 val 中使用 KFunction,但它似乎无法推断出参数。
  • 例如:Delegate(foo::doSomething).execute("1", "2", false)。我正在探索架构的一些可能性,创建中间组件而不必创建一个“空”类来拥有中间组件
  • 我更新了答案。
  • 谢谢,我也考虑过这个并创建了 FunctionN 变体,然后我认为即使这样参数名称也不会被识别为原始名称,而只会被识别为 p0、p1、p2 等;并且可能会让开发人员更加困惑:P。还是谢谢你!
猜你喜欢
  • 2017-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-04
  • 2015-09-20
  • 1970-01-01
相关资源
最近更新 更多