如何强制 Kotlin 在 Java 接口中调用特定的重载方法?
How to force Kotlin to call a particular overloaded method in Java interface?
有一个Java界面
interface MyContract {
<M> void execute(Class<M> argClass, Consumer<M> action);
<M, R> R execute(Class<M> argClass, Function<M, R> action);
}
当默认情况下从 Kotlin 代码调用 execute
方法时,编译器总是使用第一个重载方法,即使显式设置了预期类型,也会出现编译错误:
MyContract myContract = createSomehow();
val x: Int = myContract.execute(SomeClass::class.java, { it -> 1})
Compilation error:
Type mismatch: inferred type is Unit but Int was expected
为了强制编译器使用第二个重载方法,我添加了这个样板文件:
val fn: (SomeClass) -> Int = { it -> 1 }
val x: Int = myContract.execute(SomeClass::class.java, fn)
在这种情况下,表达调用特定重载方法的意图的正常语法方式是什么?
这个问题不是java-interop特有的,如果在Kotlin中定义了类似的接口,错误也会是一样的。看来还有改进重载解析机制的空间。
您可以使用以下事实作为变通方法,即重载方法具有不同数量的类型参数,因此您可以明确指定它们:
val x = myContract.execute<SomeClass, Int>(SomeClass::class.java) { it -> 1 }
这仍然很吵,所以我建议声明 Kotlin-specific API:
internal inline fun <reified M> MyContract.execute(noinline action: ((M) -> Unit)?) = execute(M::class.java, action)
internal inline fun <reified M, R> MyContract.execute(noinline action: ((M) -> R)?) = execute(M::class.java, action)
现在可以调用:
val x = myContract.execute<SomeClass, Int> { it -> 1 }
有一个Java界面
interface MyContract {
<M> void execute(Class<M> argClass, Consumer<M> action);
<M, R> R execute(Class<M> argClass, Function<M, R> action);
}
当默认情况下从 Kotlin 代码调用 execute
方法时,编译器总是使用第一个重载方法,即使显式设置了预期类型,也会出现编译错误:
MyContract myContract = createSomehow();
val x: Int = myContract.execute(SomeClass::class.java, { it -> 1})
Compilation error:
Type mismatch: inferred type is Unit but Int was expected
为了强制编译器使用第二个重载方法,我添加了这个样板文件:
val fn: (SomeClass) -> Int = { it -> 1 }
val x: Int = myContract.execute(SomeClass::class.java, fn)
在这种情况下,表达调用特定重载方法的意图的正常语法方式是什么?
这个问题不是java-interop特有的,如果在Kotlin中定义了类似的接口,错误也会是一样的。看来还有改进重载解析机制的空间。
您可以使用以下事实作为变通方法,即重载方法具有不同数量的类型参数,因此您可以明确指定它们:
val x = myContract.execute<SomeClass, Int>(SomeClass::class.java) { it -> 1 }
这仍然很吵,所以我建议声明 Kotlin-specific API:
internal inline fun <reified M> MyContract.execute(noinline action: ((M) -> Unit)?) = execute(M::class.java, action)
internal inline fun <reified M, R> MyContract.execute(noinline action: ((M) -> R)?) = execute(M::class.java, action)
现在可以调用:
val x = myContract.execute<SomeClass, Int> { it -> 1 }