有没有办法将函数的返回类型指定为被调用对象的类型?
例如
trait Foo {
fun bar(): <??> /* what to put here? */ {
return this
}
}
class FooClassA : Foo {
fun a() {}
}
class FooClassB : Foo {
fun b() {}
}
// this is the desired effect:
val a = FooClassA().bar() // should be of type FooClassA
a.a() // so this would work
val b = FooClassB().bar() // should be of type FooClassB
b.b() // so this would work
实际上,这将大致等同于instancetype
或Swift中的Self
。
7条答案
按热度按时间bvhaajcl1#
没有语言特性支持这一点,但你可以使用递归泛型(这是许多库使用的模式):
8nuwlpux2#
你可以用extension functions返回一些东西自己的类型。
eqzww0vc3#
您可以使用extension method来实现“返回相同类型”的效果。这里有一个快速的例子,展示了一个带有多个类型参数的基类型和一个扩展方法,该方法接受一个对所述类型的示例进行操作的函数:
由于扩展方法是静态解析的(至少从M12开始),如果您需要特定于类型的行为,您可能需要让扩展将实际实现委托给它的
this
。aiqt4smr4#
递归类型绑定
您在问题中显示的模式在JVM世界中被称为 * 递归类型绑定 *。递归类型是包含一个函数的类型,该函数使用该类型本身作为其参数或返回值的类型。在您的示例中,您使用相同的类型作为返回值,即
return this
。示例
让我们用一个简单而真实的例子来理解这一点。我们将用
interface
替换示例中的trait
,因为trait
现在在Kotlin中已被弃用。在本例中,接口VitaminSource
返回不同维生素源的不同实现。在下面的
interface
中,您可以看到其类型参数将自身作为上限。这就是为什么它被称为递归类型绑定:VitaminSource.kt
我们取消了
UNCHECKED_CAST
警告,因为编译器不可能知道我们是否传递了相同的类名作为类型参数。然后我们用具体的实现扩展
interface
:胡萝卜.kt
在扩展类时,必须确保将相同的类传递给接口,否则将在运行时获得
ClassCastException
:Test.kt
就这样!希望对你有帮助。
qaxu7uf25#
根据具体的使用情况,scope functions可能是一个很好的替代方案。对于构建器模式,
apply
似乎是最有用的,因为上下文对象是this
,作用域函数的结果也是this
。考虑这个例子,一个
List
的构建器有一个专门的构建器子类:然而,这只有在所有方法都有
this
作为结果时才有效。如果其中一个方法实际上创建了一个新示例,那么该示例将被丢弃。这是基于this answer的一个类似的问题。
xu3bshqb6#
vojdkbi07#
您也可以通过扩展功能来实现。