[英]Kotlin: constructor reference for a parameterized type gives a compilation error
I'm trying to write in Kotlin something like the following Java code: 我试图用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();
}
}
This code compiles and works correctly: Providers.ONE
produces an instance of ProviderImpl1
, and Providers.TWO
gives an instance of ProviderImpl2
. 此代码编译和正常工作:
Providers.ONE
产生的一个实例ProviderImpl1
和Providers.TWO
给出的实例ProviderImpl2
。
Here is what I could achieve in Kotlin: 这是我在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()
}
It works, but in Java I'm able to use a constructor reference in an enum constructor. 它可以工作,但是在Java中,我可以在枚举构造函数中使用构造函数引用。 When I try to do the same in Kotlin, namely
当我尝试在科特林做同样的事情时
ONE( ::ProviderImpl1 ),
I get the following compilation error: 我收到以下编译错误:
Type mismatch: inferred type is KFunction0 but Supplier was expected
类型不匹配:推断的类型为KFunction0,但应为供应商
A lambda without explicit type does not work either: 没有显式类型的lambda也不起作用:
ONE( ::ProviderImpl1 )
gives 给
Type mismatch: inferred type is () -> ProviderImpl1 but Supplier was expected
类型不匹配:推断的类型为()-> ProviderImpl1,但是期望供应商
The question is: does Kotlin specification prohibit this (and if yes, why, as Java seems to cope with it), or this is just a temporary imperfection of the current Kotlin compiler? 问题是:Kotlin规范是否禁止这种情况(如果是,是为什么,正如Java似乎要解决的那样),或者这仅仅是当前Kotlin编译器的暂时缺陷?
My build.gradle
has the following 我的
build.gradle
具有以下内容
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.2.61'
}
Kotlin language version is displayed by Idea (in project settings) as 1.2. Idea在项目设置中将Kotlin语言版本显示为1.2。
If you change your Supplier
to a lambda, this can be achieved quite nicely in Kotlin... 如果将
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()
}
The change here is to hand in a function that returns a Provider
instance (which is essentially what a Suppiler
is). 此处的更改是传递返回
Provider
实例的函数(本质上是Suppiler
功能)。 This is nice because if, in the future, your Provider
implementation needs some kind of configuration as it is being constructed, this lambda can handle that. 很好,因为如果将来您的
Provider
实现在构造时需要某种配置,则此lambda可以处理该配置。
If your provider is stateless, you could get away with changing Providers.provider()
into a val
, where it will only be created once per enum type. 如果您的提供程序是无状态的,则可以通过将
Providers.provider()
更改为val
,在该方法中,每个枚举类型仅创建一次。
You can use kotlin.reflect.KFunction0
like the compilation error suggests instead of java.util.function.Supplier
and then you can use the method reference. 您可以像编译错误建议那样使用
kotlin.reflect.KFunction0
而不是java.util.function.Supplier
,然后可以使用方法引用。
Example: 例:
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()
}
In this case the error message suggests that it expects an interface kotlin.reflect.KFunction0
other than java.util.function.Supplier
, so there is no prohibition for using method references in this constructor. 在这种情况下,错误消息表明它期望使用
java.util.function.Supplier
以外的接口kotlin.reflect.KFunction0
,因此不禁止在此构造方法中使用方法引用。 You can use it, you just need to use the expected interface. 您可以使用它,只需要使用预期的接口即可。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.