Scala中可重写的默认类型参数

时间:2019-06-25 16:02:34

标签: scala

我正在尝试公开一个使用类型别名参数化的类:

trait Tr[T] {
  var x: T = _
}

abstract class Foo {
  type MyParameter

  class SomeClass extends SomeOtherClass with Tr[MyParameter]
}

class Bar extends Foo {
  override type MyParameter = Int

  val myObj = new SomeClass
  myObj.x = 6
}

class Qux extends Foo {
  override type MyParameter = String

  val myObj = new SomeClass
  myObj.x = "hello" 
}

这很好。

现在,我要为MyParameter类型指定一个默认值。像这样:

abstract class Foo {
  type MyParameter = String
  // ...
}

// ...

class Qux extends Foo {
  val myObj = new SomeClass
  myObj.x = "hello"
}

但是,如果我这样做,类Bar将因类型错误而失败-显然,在这一点上,SomeClass已被固定为String

该如何解决?或者,我可以采取什么其他方法使SomeClass由具有默认类型的参数进行参数化,但是可以在Foo的子类中进行覆盖?

请注意,SomeClass比显示的要复杂,因此我不希望用户必须重写SomeClass的定义。另外,对X.SomeClass的所有使用都应使用相同的Tr[T],所以我不想使SomeClass本身可参数化。

1 个答案:

答案 0 :(得分:1)

如果您省略分配,则可以找到问题的根本原因:

scala> :paste
// Entering paste mode (ctrl-D to finish)

trait T[T] {
  var x: T = _
}

abstract class Foo {
  type Param = String

  class Child extends T[Param]
}

class Bar extends Foo {
  (new Child).x = "foo"
}

class Qux extends Foo {
  override type Param = Int
}

// Exiting paste mode, now interpreting.

<pastie>:26: error: overriding type Param in class Foo, which equals String;
 type Param has incompatible type
  override type Param = Int

覆盖类型遵循与覆盖defvalvar相同的规则:覆盖类型必须与其所覆盖的类型兼容。

例如,您无法重写toString来返回Int的方法。

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Test {
  override def toString: Int = 1
}

// Exiting paste mode, now interpreting.

<pastie>:12: error: overriding method toString in class Object of type ()String;
 method toString has incompatible type
  override def toString: Int = 1
               ^

我的建议是拆分层次结构,因此当您需要将具有Foo的{​​{1}}转换为Tr[String]时,如果需要其他类型,则可以扩展{{1 }}。