Scala中Trait如何定义返回其子类型的方法?
问题描述
现有Scala trait及子类定义如下:
@ trait Foo { def withStuffAdded(str: String): Foo } defined trait Foo
@ class X(val str: String) extends Foo { override def withStuffAdded(s: String): Foo = new X(str + s) } defined class X
尝试定义函数something时触发编译错误:
@ def something(x: X): X = x.withStuffAdded("something") cmd3.sc:1: type mismatch; found : ammonite.$sess.cmd1.Foo required: ammonite.$sess.cmd2.X def something(x: X): X = x.withStuffAdded("something") ^ Compilation Failed
报错原因是withStuffAdded声明返回Foo类型,但我们需要它返回调用者的实际子类型(如X),以满足函数something的返回值要求。
解决方案
使用**F-bounded多态(自类型参数)**修改Foo的定义,让trait能够引用自身的子类型,从而让withStuffAdded返回具体子类型:
修改后的Trait定义
@ trait Foo[Self <: Foo[Self]] { def withStuffAdded(str: String): Self } defined trait Foo
调整子类X的实现
@ class X(val str: String) extends Foo[X] { override def withStuffAdded(s: String): X = new X(str + s) } defined class X
验证函数编译
此时重新定义something即可正常通过编译:
@ def something(x: X): X = x.withStuffAdded("something") defined function something
原理说明
- 给
Foo添加自类型参数Self,并通过<: Foo[Self]限制该参数必须是Foo的子类,强制子类继承时传入自身作为类型参数。 - 将
withStuffAdded的返回类型改为Self,这样子类实现时可以返回自身类型,编译器能准确识别返回值的具体类型,消除类型不匹配的错误。
内容的提问来源于stack exchange,提问作者Kevin Meredith
相关产品推荐
相关产品推荐

