gpt4 book ai didi

kotlin - 使用反射调用具有默认参数值的函数

转载 作者:行者123 更新时间:2023-12-02 12:53:05 27 4
gpt4 key购买 nike

考虑一个接口(interface):

interface Foo {
fun func(argWithDefault: String = "default")
}

及其(最小)实现:
class FooImpl() : Foo {
override fun func(argWithDefault: String) {
println(argWithDefault)
}
}

我也在尝试调用 funcFooImpl通过反射:
val func = Foo::func
val instance = FooImpl()
func.callBy(mapOf(func.instanceParameter!! to instance))

但我得到以下异常:

kotlin.reflect.jvm.internal.KotlinReflectionInternalError: This callable does not support a default call: public abstract fun func(argWithDefault: kotlin.String = ...): kotlin.Unit defined in com.example.Foo[DeserializedSimpleFunctionDescriptor@2d7275fc]


Foo::func.parameters[1].isOptional返回 true ,并且根据文档, isOptional返回

true if this parameter is optional and can be omitted when making a call via KCallable.callBy, or false otherwise.



所以我想这应该是可能的。

最佳答案

tl;博士:这似乎是一个已知问题:KT-13936: KotlinReflectionInternalError on invoking callBy on overridden member with inherited default argument value

我之前做过的一些分析:

如果我们看看 Kotlin 在这里实际生成的内容,就会很明显为什么你不再有任何默认值了。 Foo 的字节码:

public abstract interface Foo {

public abstract func(Ljava/lang/String;)V
LOCALVARIABLE this LFoo; L0 L1 0
LOCALVARIABLE argWithDefault Ljava/lang/String; L0 L1 1

public final static INNERCLASS Foo$DefaultImpls Foo DefaultImpls
}


// ================Foo$DefaultImpls.class =================
public static synthetic func$default(LFoo;Ljava/lang/String;ILjava/lang/Object;)V
ALOAD 3
IFNULL L0
NEW java/lang/UnsupportedOperationException
DUP
LDC "Super calls with default arguments not supported in this target, function: func"
INVOKESPECIAL java/lang/UnsupportedOperationException.<init> (Ljava/lang/String;)V
ATHROW
L0
ILOAD 2
ICONST_1
IAND
IFEQ L1
L2
LINENUMBER 2 L2
LDC "default" // <--- here is our default value? but where are we? Foo$Defaults.func$default?
ASTORE 1
L1
ALOAD 0
ALOAD 1
INVOKEINTERFACE Foo.func (Ljava/lang/String;)V (itf)
RETURN
MAXSTACK = 3
MAXLOCALS = 4

public final static INNERCLASS Foo$DefaultImpls Foo DefaultImpls
// compiled from: Foo.kt
}

所以 Foo中声明的函数只是 fun foo(String) ... 任何地方都没有默认值,除了在它自己的合成函数中 DefaultImpls -类(class)。

那么那个函数在哪里调用... FooImpl也许?

如果我们查看 FooImpl -bytecode 很明显它不存在:
public final class FooImpl implements Foo {

public func(Ljava/lang/String;)V
L0
ALOAD 1
LDC "argWithDefault"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 3 L1
L2
ICONST_0
ISTORE 2
L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L4
L5
LINENUMBER 4 L5
RETURN
L6
LOCALVARIABLE this LFooImpl; L0 L6 0
LOCALVARIABLE argWithDefault Ljava/lang/String; L0 L6 1
MAXSTACK = 2
MAXLOCALS = 3

...

因此,为了完整起见,我还创建了 Caller.kt仅包含以下代码:
fun main() = FooImpl().func()

最后是字节码,还有我们的 DefaultImpls.func$default -称呼:
public final class CallerKt {


public final static main()V
L0
LINENUMBER 1 L0
NEW FooImpl
DUP
INVOKESPECIAL FooImpl.<init> ()V
ACONST_NULL
ICONST_1
ACONST_NULL
INVOKESTATIC Foo$DefaultImpls.func$default (LFoo;Ljava/lang/String;ILjava/lang/Object;)V // aha! here is our DefaultImpls.func$default!
RETURN
L1
MAXSTACK = 4
MAXLOCALS = 0

所以...作为 DefaultImpls由编译器生成并在需要时使用, reflect实用程序也可以(并且在我看来应该)反射(reflect)这个事实......我在答案的顶部添加了一个关于开放类(也使用合成 ...$default -functions)的类似已知问题。如果该问题不能完全解决您的问题,您可能需要打开一个新的 Kotlin issue反而。

刚刚玩了一下链接的问题......实际上,如果 A::foo,那里的样本会起作用。用于代替 B::foo ( A 是开放类, B 扩展了 A )。然而作为 A基本上与您的 Foo 类似-interface,但是接口(interface)需要对此进行特殊处理。

关于kotlin - 使用反射调用具有默认参数值的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55948868/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com