【问题标题】:Inferring parameter of class type with default使用默认推断类类型的参数
【发布时间】:2018-02-06 12:57:16
【问题描述】:

我有一个这样声明构造函数的类

class Facade<T : SuperClass>(
    val kClass: KClass<in T> = SuperClass::class
)

这样做是为了让开发人员在想要使用 SuperClass 而不是子类时不必指定 SuperClass。 甚至发送类类型的原因是,这样开发人员就不必在尖括号中指定类型。

但现在问题来了。像下面这样创建实例,表示没有足够的信息来推断参数 T。这导致必须将类放入尖括号中。

Facade()

但是由于默认值是 SuperClass,那么 kotlin 应该能够将参数 T 推断为 SuperClass。我在想什么?

谢谢

TL;DR:

Facade(SubClass:class) // working
Facade(SuperClass:class) // working, but don't want (superclass is default)
Facade<SuperClass>() // working, but don't want angle brackets <>
Facade() // not working, cannot infer T type from default, why?

【问题讨论】:

    标签: android kotlin kotlin-generics


    【解决方案1】:

    要使Facade() 等效于Facade(DerivedClass::class),默认构造函数参数必须声明为val kClass: KClass&lt;in T&gt; = T::class。但是要使用T::classT 类型参数需要为reified。类型参数只能在内联函数中具体化,而不能在构造函数中具体化。

    要解决此问题,您可以声明一个委托给构造函数的工厂函数,如下所示:

    inline fun <reified T : SuperClass> Facade(): Facade<T> = Facade(T::class)
    

    这允许人们将其用作例如:

    val derivedFacade:Facade<DerivedClass> = Facade()
    

    请注意,如果您想使用SuperClass 作为T 的默认参数,您需要使用不同的名称 声明另一个工厂方法,例如:

    fun SuperFacade(): Facade<SuperClass> = Facade()
    

    这是必需的,因为如果我们声明了@JvmName("SuperFacade") fun Facade() = Facade(SuperClass::class),只要我们不提供类型参数,编译就会匹配它。这反过来又会违背derivedFacade 示例中的类型推断。

    【讨论】:

      【解决方案2】:

      您可以通过删除尖括号并更改构造函数类型来解决您的问题。 只需使用此构造函数:

      class Facade(val kClass: KClass<*> = SuperClass::class)
      

      所有这些调用都有效

      Facade(SubClass:class)
      Facade(SuperClass:class)
      Facade()
      

      【讨论】:

      • 哦,不错。我的错误我没有指定它,但实际上我确实需要 T 来表示属性和方法。另外,我无法设定 SuperClass 的上限(只有超类及其派生类可以转到此构造函数)。
      猜你喜欢
      • 2021-12-22
      • 2016-10-11
      • 1970-01-01
      • 2022-01-06
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多