“无法计算函数的调用者”:如何反射性地调用“plus”?

问题描述 投票:0回答:1

在函数

f
中,我想对两个值
a.x
b.x
求和:

class C<T>(var x: T)

inline fun <reified T> f(a: C<T>, b: C<T>): T? {
    val c = T::class
    val members = c.members.groupBy { it.name }
    for (m in members["plus"]!!) {
        if (m.parameters[1].type == Int::class.createType()) {
            return m.call(a.x, b.x) as T?
        }
    }

    return null
}

fun main(args: Array<String>) {
    val a = C(1)
    val b = C(2)
    println(f(a, b))
}

错误:

Exception in thread "main" kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Could not compute caller for function: @kotlin.internal.IntrinsicConstEvaluation public final operator fun plus(other: kotlin.Int): kotlin.Int defined in kotlin.Int[DeserializedSimpleFunctionDescriptor@2f4205be] (member = null)
    at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:98)
    at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:64)
    at kotlin.SafePublicationLazyImpl.getValue(LazyJVM.kt:107)
    at kotlin.reflect.jvm.internal.KFunctionImpl.getCaller(KFunctionImpl.kt:64)
    at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108)
    at MainKt.main(Main.kt:66)
kotlin reflection
1个回答
0
投票

目前这是不可能的。

Int::plus
实际上并不存在,因为没有对应的 JVM 方法。您无法致电
Int::plus

当像

someInt + anotherInt
这样的东西被编译时,它不会被转换为对
Int::plus
的调用。它只是直接翻译成
iadd
JVM 指令。

最终,Kotlin 反射会尝试查找相应的 JVM 方法,因此当找不到时,它会抛出

KotlinReflectionInternalError
。请参阅
KFunctionImpl

中的实现
val member: Member? = when (val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor)) {
    // ...
    is KotlinFunction -> {
        // ...
        container.findMethodBySignature(jvmSignature.methodName, jvmSignature.methodDesc) as Member?
    }
    // ...
}

when (member) {
    is Constructor<*> -> // ...
    is Method -> // ...
    else -> throw KotlinReflectionInternalError("Could not compute caller for function: $descriptor (member = $member)")
}.createValueClassAwareCallerIfNeeded(descriptor)

您可以看到,Kotlin 函数首先映射到其 JVM 签名,然后使用

container.findMethodBySignature
Int
中查找具有该签名的 JVM 方法。这样的方法不存在,所以
container.findMethodBySignature
返回null,并且在第二个
when
中抛出异常。

已经有错误报告报告了此问题。例如,请参阅KT-13077(及其相关问题)。 KT-13077 (

Int::toByte
) does 中提到的具体情况有点像 JVM 对应项 (
java.lang.Integer::byteValue
),而且它们还使用可调用引用表达式,这使得异常消息与您的有点不同.

无论如何,这是 Kotlin 反射还无法做到的事情。

© www.soinside.com 2019 - 2024. All rights reserved.