简体   繁体   English

Kotlin:参数化类型的构造函数引用给出了编译错误

[英]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产生的一个实例ProviderImpl1Providers.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.

相关问题 传递参数化构造函数作为方法引用 - pass parameterized constructor as method reference 参数化构造函数错误 - Parameterized Constructor Error 为什么在参数化构造函数中出现此错误? - Why is this error in parameterized constructor? 使用 Kotlin 实现 MongoDB CodecProvider 给出类型不匹配编译错误 - Implementing MongoDB CodecProvider with Kotlin giving Type mismatch Compilation Error 在构造函数上声明返回类型不会导致编译错误 - declaring a return type on a constructor doesn't cause a compilation error 编译参数化构造函数代码期间的Eclipse错误 - Eclipse error during compilation of a parameterized contructor code Kotlin Pass输入可实现参数化接口的类型 - Kotlin Pass in a type that implements a parameterized interface 错误:不能对构造函数使用带有显式类型参数的原始构造函数引用 - Error: cannot use raw constructor reference with explicit type parameters for constructor 抽象类:为什么newInstance()没有给出编译错误但构造函数调用给出了错误? - Abstract class : Why newInstance() is not giving compilation error but constructor call gives error? Java反射中这个Constructor的参数化类型是什么? - What is the parameterized type of this Constructor in Java reflection?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM