我想发布How to use Scala's this typing, abstract types, etc. to implement a Self type?答案的后续内容 但我不能因为我没有足够的声誉来发布后续行动。
我有一个抽象类型,并希望在函数中返回具体类型的实例,以便能够在另一个参数化函数中使用此函数:
trait Abstract {
def test(): <concrete type>
}
class Concrete extends Abstract {
override def test(): Concrete = new Concrete
}
def fun[C <: Abstract](c: C): C = c.test()
使用this.type
的第一个解决方案对我不起作用,因为我希望能够在Concrete
方法中返回test()
的新实例。
所以我尝试了第二个解决方案:
trait Abstract {
type Self <: Abstract
def test(): Self
}
class Concrete extends Abstract {
override type Self = Concrete
override def test(): Concrete = new Concrete
}
但它无法编译:
def fun[C <: Abstract](c: C): C = c.test()
> [error] type mismatch;
> [error] found : c.Self
> [error] required: C
这是非常符合逻辑的,因为我可以在Self
的另一个具体实现中覆盖Abstract
类型。
我想避免的是:
trait Abstract2[C] {
def test(): C
}
class Concrete2 extends Abstract2[Concrete2] {
override def test(): Concrete2 = new Concrete2
}
def fun2[C <: Abstract2[C]](c: C): C = c.test()
因为客户使用起来比较困难。还有其他可能吗?
答案 0 :(得分:0)
您想要的签名是错误的,因为它允许以下代码:
val c1: Concrete = new Concrete
val c2: c1.type = fun[c1.type](c1)
但fun(c1)
返回的值不是c1
,因此没有c1.type
类型。
但您可以将其更改为def fun[C <: Abstract](c: C): c.Self = c.test()
。如果C
为Abstract
,则编译器知道c.Self
是Abstract
的子类型,并且可以在可以使用所需签名的返回值的任何位置使用返回值。如果C
为Concrete
,则c.Self
为Concrete
。如果上例中的C
为c1.type
,则c2
的类型仍为Concrete
。