【问题标题】:How can I write an interface with a static function that returns Self in Kotlin?如何编写一个带有在 Kotlin 中返回 Self 的静态函数的接口?
【发布时间】:2021-08-05 21:18:17
【问题描述】:
我正在尝试编写与 Swift 中类似的 Kotlin 版本:
protocol Parseable {
static func parse(json: JSON) -> Self
}
我找不到如何定义一个需要静态方法的接口,也找不到如何引用接口中的实现类型。
【问题讨论】:
-
self 到底是什么意思?和java中的this一样吗?如果是,则无法编写上述代码,因为静态方法无法访问this reference。你可以多看here
-
标签:
kotlin
interface
static-methods
【解决方案1】:
我不知道 Swift,但看起来你在谈论“自我类型”——它表示实现接口的类的类型。
不幸的是,Kotlin 没有 self 类型。 (请参阅here,了解关于添加它的前景的长期讨论。)
在 Kotlin(和 Java)中通常的解决方法是创建接口 generic,并将实现类作为类型参数。 (我认为这种模式没有特定的名称,但 C++ 中的等价物称为curiously-recurring template pattern。)
但是,所讨论的方法是静态的,因此该模式不能直接应用。
你所拥有的看起来像一个工厂,并且有几种方法可以实现——我不确定哪种方法最符合你的 Swift 代码,但每种方法都可以使用泛型。你可以有一个工厂类,为你想要创建的每种类型的 Parseable 提供一个实例;在这种情况下,工厂类可以有一个类型参数。或者,您可能有一个单例工厂对象、一个伴生对象或一个顶级工厂函数;在这些情况下,函数本身可以是通用的。
下面是工厂函数的样子:
fun <P : Parseable> parse(json: JSON): P {
// Code that returns a value of type P
}
(实际上,您可能会发现您需要访问 P 的某些详细信息,由于type erasure,这些详细信息通常在运行时不可用。 但是您可以通过设置 P @987654325 来解决这个问题@——也需要函数是inline。)
根据上下文,调用者可能需要指定类型,例如:
val result = parse<MyParseable>(json)
(IDE 通常会让你知道你是否需要提供类型,或者编译器是否可以推断它。)
【解决方案2】:
Kotlin 具有实际上相似的伴生对象,而不是静态对象。
我们可以通过扩展一个类或在一个伴生对象上实现一个接口来做看起来像静态继承的事情。并且没有自类型,但我们可以使用泛型。
interface Parseable <T> {
fun parse(json: Json): T
}
class Foo {
companion object: Parseable<Foo> {
override fun parse(json: Json): Foo {
TODO("Not yet implemented")
}
}
}
fun testParsingFoo(json: Json) {
Foo.parse(json)
}
我不熟悉 Swift,所以如果我误解了这个问题,请告诉我。但我认为这与您所要求的 Kotlin 等价。
【解决方案3】:
获得类似于 self 类型(Kotlin 没有)的一种方法是使用通用接收器在接口之外创建扩展函数。
interface Parseable {
}
fun <T: Parseable> T.parse(json: JSON): T {
// implementation
return this
}
可以在任何实现 Parseable 的对象上调用此扩展函数,并将返回调用它的实例,编译器会将其识别为自己的类型,而不仅仅是 Parseable。