我有一个带有像这样声明的构造函数的类
class Facade<T : SuperClass>(
val kClass: KClass<in T> = SuperClass::class
)
这样做是为了让开发人员不必指定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?
答案 0 :(得分:0)
要使Facade()
等效于Facade(DerivedClass::class)
,默认构造函数参数必须声明为val kClass: KClass<in T> = T::class
。但是,要使用T::class
,T
类型参数必须为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
示例中的类型推断。
答案 1 :(得分:0)
您可以通过删除尖括号并更改构造函数类型来解决问题。 只需使用此构造函数:
class Facade(val kClass: KClass<*> = SuperClass::class)
所有这些电话都在运作
Facade(SubClass:class)
Facade(SuperClass:class)
Facade()