为具有不同类型参数的类型定义公共特征

时间:2015-11-22 16:53:19

标签: scala generics

假设我有两个特征:

trait Generic1[T] {
  def mapR[U](f: Result[T] => Result[U]): Generic1[U]
}

trait Generic2[A, T] {
  // pretty much the same as Generic1, but with the extra `A` type param
  def mapR[U](f: Result[T] => Result[U]): Generic2[A, U]
}

有没有办法可以定义一个基于mapR方法定义一些常用功能的特征?

// for example
trait MapR[T, ???] {
  def mapR[U](f: Result[T] => Result[U]): ???[U]

  def map[U](f: T => U): ???[U] = mapR(_ map f)
  def flatMap[U](f: T => Result[U]): ???[U] = mapR(_ flatMap f)
  def withFilter(f: T => Boolean): ???[T] = mapR(_ withFilter f)
}

如何在上面的???特征中定义MapR,以便我可以改为定义

trait Generic1[T] extends MapR[T, ???]
trait Generic2[A, T] extends MapR[T, ???]

额外问题

@ m-z的答案处理上面提到的问题,但是当GenericN特征具有类型差异时,我遇到了一些麻烦:

trait Generic1[+T] extends MapR[T] {
  type R[X] = Generic1[X]
  ...
}
trait Generic2[-A, +T] extends MapR[T] {
  type R[X] = Generic2[A, X]
  ...
}

我得到类似“逆变类型A出现在类型为[X] Generic2 [A,X]中的不变位置”的错误

我尝试重新定义R是协变的,但它仍然没有触及A类型,我也遇到了类似的错误。

答案中的方法是否可以调整以处理上述的类型差异?

2 个答案:

答案 0 :(得分:2)

您可以使MapR特征具有单个类型参数的类型成员,而不能实现Generic特征的别名。这将需要每个Generic特征来描述它的参数化方式。

trait Result[T]

trait MapR[T] {

  type R[U]

  def mapR[U](f: Result[T] => Result[U]): R[U]

}

trait Generic1[T] extends MapR[T] {
  type R[U] = Generic1[U]
}

trait Generic2[A, T] extends MapR[T] {
  type R[U] = Generic2[A, U]
}

答案 1 :(得分:1)

你可能可以通过宣布超高级管理来实现这一目标。沿着这些方向的东西可能是可能的:

trait Result[T]

trait MapRSupport[SelfType[X], T] {
  def mapR[U](f: Result[T] => Result[U]): SelfType[U]
}

trait Generic1[T] extends MapRSupport[Generic1, T]{
  def mapR[U](f: Result[T] => Result[U]): Generic1[U] = ???
}

trait Generic2[A] extends MapRSupport[Generic2, A]{
  type T
  // pretty much the same as Generic1, but with the extra `A` type param
  def mapR[U](f: Result[T] => Result[U]): Generic2[A] { type T = U} = ???
}