0

看来我在这里遗漏了一些非常重要的东西。Kotlin 函数类型是用称为Function N的特定类实现的,并使用泛型来定义接收器、参数和返回类型。存储函数引用时,是否有可以保留函数签名的语法?或者任何其他方式来执行我在下面的代码中所做的事情?

那是因为这一切都很有趣和游戏,直到您希望将它们实际存储为类型Any ,比如在 a中,然后检索它们,匹配并将它们向下转换/分配给函数变量并使用它。问题是泛型会执行Type Erasure,因此如果您将函数存储到Any,您将无法将其取回并使用它,即将其 与实际类型匹配将是: 并且不可用,因为它仅将签名与参数匹配无类型,即你已经完成了。(您可以使用它的唯一情况是因为它没有参数或返回类型。)Map<String,Any>Function2<Int,Int,Int>Function2<*,*,*>Function0

编译类型函数签名和运行时函数签名之间似乎存在脱节。

由于样板文件以及我必须使用类继承来键入函数签名这一事实,我设法通过以下我讨厌的代码克服了这个问题。我知道强制转换需要代码对存储的对象有额外的了解,并且可以被认为是一种反模式,但是如何存储函数以供以后动态调用呢?(可能有其他数据将匹配应用程序/服务器中的参数和类型,其他模块都将声明它们自己的函数。在下面的示例中,类仅声明一个绑定到签名类型的函数,在一个完整的示例中这些类将在构造函数中使用一个实际的 lambda,即每个实例Function2IntToInt指向另一个函数,因此它有 2 个层次:签名和函数指针。

感谢您的善意见解和建议。

编辑:澄清和拼写

// used as receiver object
class Zar(var v:Int) {}

// base class to represent all functions
open class Func 

// 2 function examples, all function signatures will be 1 level deep inheritance.

class Function2IntToInt : Func() {
    val func = fun Zar.(x:Int,y:Int): Int { return x+y+v}
}
//clarification: fixed example used above, could also have been:
//class Function2IntToInt(var func: Zar.(Int,Int)->Int) : Func() {}

class FunctionStringToInt : Func() {
    val func = fun (s:String): Int { return s.length}
}

fun main() {
    var a = Zar(1)
   
    // these 2 could be stored into a collection of type Map<String,Func>
    var func:Func = Function2IntToInt()
    var func2:Func = FunctionStringToInt()
    
    // function retrieval
    var func3:Func = func
    // casting. It could fail if function storage was mismatched, but not here.
    var iface = func3 as Function2IntToInt
    var f = iface.func

    println("Invocation: result must match 3: " + a.f(1,1))

}

4

1 回答 1

0

由于 JVM 的类型擦除,您存储在多个子类型集合中的任何类型都将面临同样的问题。在这种情况下,铸造是不可避免的。对于函数,您必须创建更高种类的包装器类型,就像您必须能够按类型检索它们一样。通过将项目按类型存储在单独的列表中,在类型为键的映射中,您可以更好地证明这一点。

val foo = mutableMapOf<Func, MutableMap<String, Func>>()

fun <T: Func> storeItem(item: T, name: String) {
  foo.getOrPut(bar::class, ::mutableMapOf)[name] = item
}

inline fun <reified T: Func> retrieveItem(name: String): T? {
  return foo[T::class]?.get(name) as T?
}

请注意,您并不严格需要Func超级类型。您可以在上面的代码中将其替换为 Any 并让您的实现直接从其功能定义继承:

abstract class FunctionStringToInt: (String) -> Int

class MyStringToIntImpl: FunctionStringToInt() {
  override fun invoke(s: String): Int {
    return s.length
  }
}
于 2020-09-24T04:26:57.220 回答