Scala在参数化函数中返回自我类型

时间:2017-03-15 15:03:42

标签: scala types

我想发布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()

因为客户使用起来比较困难。还有其他可能吗?

1 个答案:

答案 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()。如果CAbstract,则编译器知道c.SelfAbstract的子类型,并且可以在可以使用所需签名的返回值的任何位置使用返回值。如果CConcrete,则c.SelfConcrete。如果上例中的Cc1.type,则c2的类型仍为Concrete