我正在尝试用Kotlin编写类似以下Java代码的内容:
interface Provider {
}
class ProviderImpl1 implements Provider {
}
class ProviderImpl2 implements Provider {
}
enum Providers {
ONE(ProviderImpl1::new),
TWO(ProviderImpl2::new);
private final Supplier<Provider> supplier;
Providers(Supplier<Provider> supplier) {
this.supplier = supplier;
}
public Provider provider() {
return supplier.get();
}
}
此代码可以编译并正常工作:Providers.ONE
生成ProviderImpl1
的实例,而Providers.TWO
给出ProviderImpl2
的实例。
这是我在Kotlin可以实现的目标:
interface Provider {
}
class ProviderImpl1 : Provider {
}
class ProviderImpl2: Provider {
}
enum class Providers(private val factory: Supplier<Provider>) {
ONE(Supplier{ ProviderImpl1() }),
TWO(Supplier{ ProviderImpl2() });
fun provider(): Provider = factory.get()
}
它可以工作,但是在Java中,我可以在枚举构造函数中使用构造函数引用。当我尝试在Kotlin中做同样的事情时,
ONE( ::ProviderImpl1 ),
我收到以下编译错误:
类型不匹配:推断的类型为KFunction0,但期望供应商
没有显式类型的lambda也不起作用:
ONE( ::ProviderImpl1 )
给予
类型不匹配:推断的类型为()-> ProviderImpl1,但期望供应商
问题是:Kotlin规范是否禁止这样做(如果可以,为什么,正如Java似乎要解决的那样),或者这仅仅是当前Kotlin编译器的暂时缺陷?
我的build.gradle
具有以下
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.2.61'
}
科特林语言版本由Idea(在项目设置中)显示为1.2。
答案 0 :(得分:3)
如果将Supplier
更改为lambda,则可以在Kotlin中很好地实现这一目标...
interface Provider
class ProviderImpl1 : Provider
class ProviderImpl2 : Provider
enum class Providers(private val supplier: () -> Provider) {
ONE({ ProviderImpl1() }),
TWO({ ProviderImpl2() });
fun provider(): Provider = supplier.invoke()
}
此处的更改是传递一个返回Provider
实例的函数(本质上是Suppiler
的实例)。很好,因为如果将来Provider
实现在构造时需要某种配置,则此lambda可以处理。
如果您的提供程序是无状态的,则可以将Providers.provider()
更改为val
,在此情况下,每个枚举类型只能创建一次。
答案 1 :(得分:2)
您可以像编译错误建议那样使用kotlin.reflect.KFunction0
来代替java.util.function.Supplier
,然后可以使用方法引用。
示例:
import kotlin.reflect.KFunction0
interface Provider {
}
class ProviderImpl1 : Provider {
}
class ProviderImpl2: Provider {
}
enum class Providers(private val factory: KFunction0<Provider>) {
ONE(::ProviderImpl1),
TWO(::ProviderImpl2);
fun provider(): Provider = factory.call()
}
在这种情况下,错误消息表明它期望使用kotlin.reflect.KFunction0
以外的接口java.util.function.Supplier
,因此在此构造函数中不禁止使用方法引用。您可以使用它,只需要使用预期的界面即可。