假设我有以下类,带有类型参数T(在此示例中,它有助于说明后面的示例,但是当它无界时错误仍然存在):
class GenericsTest<T : CharSequence>(private var cs: T)
现在假设我想在这个类中添加一个辅助构造函数。我怎样才能做到这一点?我的第一次(天真)尝试导致编译器错误:
class GenericsTest<T : CharSequence>(private var cs: T)
{
// dummy exists to ensure the method signatures are different
constructor(cs: String, dummy: Int) : this("a")
}
IntelliJ使用以下消息强调"a"
:
Type mismatch.
Required: T
Found: String
对我而言,String
似乎是完全有效的T
。我认为明确指定类型参数会有所帮助,但似乎不允许这样做。这两种尝试都是不正确的语法:
constructor(cs: String, dummy: Int) : this<String>("a")
constructor<U : String>(cs: U, dummy: Int) : this("a")
由于我怀疑所有这些场景都有一个共同的方法,我的主要问题是:
如何在Kotlin中为泛型类编写辅助构造函数?或者类似地,当构造函数具有类型参数时,如何委托给主构造函数?
这甚至可能吗?如果没有,一种解决方法可能是使用辅助函数来使用主构造函数创建对象,但这不适用于例如抽象类。
关于generics的官方文档没有讨论构造函数。
答案 0 :(得分:3)
对辅助函数进行分组的另一种方法是:可以调用伴随对象。
class GenericsTest<T : CharSequence>(private var cs: T) {
companion object {
operator fun invoke(cs: String, dummy: Int) = GenericsTest(cs)
}
}
GenericsTest("a", 1)
它不是一个真正的构造函数,但它看起来像一个。相对于独立函数的一个好处是,即使被调用的构造函数是private
,它也能正常工作。
答案 1 :(得分:0)
如果类具有主构造函数,则每个辅助构造函数 需要直接或者委托给主构造函数 间接通过另一个辅助构造函数。
GenericsTest
签名主构造函数声明它接受实现CharSequence
的任何类型。由于辅助构造函数类必须调用主构造函数,因此它还必须支持任何实现CharSequence
的类型。无论我们选择哪个构造函数来实例化GenericsTest
,我们都应该能够为任何 T: CharSequence
而不仅String
执行此操作,因此编译器会抱怨Type mismatch
。
您已经提到过涉及帮助函数的工作,例如:
fun GenericsTest(cs: String) = GenericsTest<String>(cs)
fun GenericsTest(cs: CharBuffer, other:Int) = GenericsTest(cs)
正如您所提到的,辅助函数不适用于抽象类。但是,抽象类允许在衍生物中进行类型特化,例如:
class StringsTest<T : String>(s: T) : GenericsTest<T>(s)
抽象基类几乎不可能或不希望(从设计角度来看,开放封闭原则)声明可以从专门用于泛型类型的派生类直接获得 的东西。