【问题标题】:Kotlin Interface function interchangeable argumentsKotlin 接口函数可互换参数
【发布时间】:2020-03-30 09:26:15
【问题描述】:

我目前正在研究一个接口,该接口具有一个简单的功能,所有扩展此接口的类都应实现该功能。 但是这些类应该可以像这样使用不同的函数参数调用

interface IDoSomething<T> {

    fun execute(vararg any: Any?): T // Make function arguments interchangeable

}
class DoSomethingA : IDoSomething<String> {

    // This is what i want
    override fun execute(int: Int, boolean: Boolean): String {
        println("Do something with parameters: $int, $boolean")
        ...  
    }

    // This is what i need to do
    override fun execute(vararg any: Any?): String {
        val int = any[0] as Int
        val boolean = any[1] as Boolean
        println("Do something with parameters: $int, $boolean")
        ...
    }
}

实现这个接口的其他类应该可以有其他参数

class DoSomethingB : IDoSomething<String> {

    // Should also be possible with same interface
    override fun execute(string: String, double: Double, boolean: Boolean): String {
        println("Do something with parameters: $string, $double, $boolean")
        ...
    }

}

Kotlin 中有什么东西可以帮助我做这样的思考吗?或者存在一种有助于解决这类问题的模式。

【问题讨论】:

  • 这违背了接口的目的。在不知道具体实现的情况下,您将无法调用该函数,因此最好从接口定义中删除该方法。但是您可以使用泛型定义一组固定的参数,然后当有一组特定参数类型的多个实现时可能会有用。

标签: generics kotlin interface


【解决方案1】:

语言中没有任何内置功能可以实现您想要的功能(例如 C++ 可变参数模板)。

但是您仍然可以使用通用输入来实现您想要的,并将多个参数替换为包装它们的类:

interface IDoSomething<I, T> {

  fun execute(input: I): T
}

class DoSomethingB : IDoSomething<Pair<String, Double>, String> {

  // Should also be possible with same interface
  override fun execute(input: Pair<String, Double>): String {
    val (string, double) = input
    println("Do something with parameters: $string, $double")
    ...
  }
}

这是解决问题的最简单方法。

你有另一个更复杂的解决方案。

您可以有一个注解(例如@Input),它接受您需要为每个实现支持的类型,然后您可以使用注解处理器生成接口的扩展以确保编译时安全。

例如

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class Input(
  val types: Array<KClass<*>> = []
)

@Input(types = [String::class, Double::class])
class DoSomethingB : IDoSomething<String> {

  override fun execute(vararg any: Any?): String = execute(any) { string, double ->
    println("Do something with parameters: $string, $double")
    ...
  }
}

// With an annotation processor you can generate an extension like this.
fun DoSomethingB.execute(vararg input: Any?, block: (string: String, double: Double) -> String): String {
  val string = input[0] as String
  val double = input[1] as Double
  return block(string, double)
}

【讨论】:

  • 谢谢。很好的解决方案。我会选择简单的。但是有注释的也很有趣
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多