在Kotlin对象成员中引用自己的类型

时间:2019-06-23 19:17:42

标签: kotlin

我有一些object像这样:

interface Maker<T : Thing>

interface Thing

我希望Thing保留对其Maker的引用,但我不知道如何:

interface Thing {
    val maker: Maker<this::class> // ??
}

这样我可以有类似的东西:

class BallMaker : Maker<Ball>

object Ball : Thing {
    override val maker = BallMaker
}

我该如何实现?

2 个答案:

答案 0 :(得分:2)

Thing的角度来看,其制造商必须简单地定义为Maker<*>,这意味着任何类型的制造商。

您可以使用子类参数化Thing

interface Maker<T : Thing<T>> {
}

interface Thing<T : Thing<T>> {
    val maker: Maker<T>
}

class Ball : Thing<Ball> {
    override val maker: Maker<Ball>
}

答案 1 :(得分:1)

如果您像这样定义Maker界面:

interface Maker<out T : Thing>
    fun make(): T
}

然后您的Thing界面可以定义为:

interface Thing {
    val maker: Maker<Thing>
}

由于使用out,可以将实现定义为:

class BallMaker : Maker<Ball> {
    override fun make(): Ball = TODO("not implemented")
}

class Ball : Thing {
    override val maker = BallMaker()
}

此处,maker属性的类型为BallMaker。您还可以使用:

override val maker: Maker<Ball> = BallMaker()

如果您希望公开接口类型而不是实现。


有关Kotlin中泛型的更多信息,请参见Generics: in, out, where - Kotlin Programming Language。关于使用out的重要一件事是:

  

一般规则是:当将类T的类型参数C声明为 out 时,它只能出现在 out 中-在C的成员中排名,但作为回报,C<Base>可以安全地成为C<Derived>的超类型。

换句话说,如果使用out定义了通用参数,则只能将其用作返回类型,而不能用作参数类型。 in则相反。


当然,如果您的Maker接口只有一种方法,则您可能需要考虑使用函数类型。

interface Thing {
    val maker: () -> Thing
}

这仍然允许您执行以下操作:

class Ball : Thing {
    // type can be inferred to "() -> Ball" instead in this case
    override val maker: () -> Ball = { Ball() }
}

如果要命名函数类型,请使用type alias