如何为具有类型参数的类编写辅助构造函数?

时间:2018-01-12 06:13:03

标签: generics constructor kotlin

假设我有以下类,带有类型参数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的官方文档没有讨论构造函数。

2 个答案:

答案 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)

作为per documentation

  

如果类具有主构造函数,则每个辅助构造函数   需要直接或者委托给主构造函数   间接通过另一个辅助构造函数。

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)

抽象基类几乎不可能或不希望(从设计角度来看,开放封闭原则)声明可以从专门用于泛型类型的派生类直接获得 的东西。