在scala 2.13+ / 3.x中,我们如何解决抽象类型的菱形继承问题?

问题描述

这是一个简单的例子:

trait Sup {

  type A

  def a: A

  def b: A
}

trait Sub1 extends Sup {

  override type A = Product

  override def a = "s" -> "s"
}

trait Sub2 extends Sup {

  override type A = Serializable

  override def b = "s" -> "s"
}

object SS extends Sub1 with Sub2

显然,这将导致编译错误,因为两个override type A是互斥的。这是违反直觉的,因为产品和可序列化通常一起使用。另外,我可以定义:

trait Sup {

  type A

  def a: A
}

trait Sub1 extends Sup {

  override type A <: Product

  override def a = "s" -> "s"
}

trait Sub2 extends Sup {

  override type A <: Serializable

  override def b = "s" -> "s"
}

object SS extends Sub1 with Sub2 {

  override type A = Product with Serializable
}

这使a和b的定义无效,因为类型A尚未得到验证,此外,override type A = Product with Serializable行显然是一个样板,可以推断出来。

定义允许菱形混合的抽象类型的正确方法是什么,同时避免在每个实现中都明确定义样板?

解决方法

我想你失去了下界。

"s" -> "s"具有类型(String,String),它是Product(和Serializable)的子类型,但不是A <: Product(或{{1} }。

尝试

A <: Serializable

如果您将返回类型trait Sup { type A def a: A def b: A } trait Sub1 extends Sup { override type A >: (String,String) <: Product override def a = "s" -> "s" } trait Sub2 extends Sup { override type A >: (String,String) <: Serializable override def b = "s" -> "s" } object SS extends Sub1 with Sub2 { override type A = Product with Serializable } SS.a: (String,String) SS.b: (String,String) implicitly[SS.A =:= (Product with Serializable)] Sub1#a指定为Sub2#b(以上推断它们为A,即方法重写时缩小了返回类型),则

(String,String)

你甚至可以做

trait Sup {
  type A
  def a: A
  def b: A
}

trait Sub1 extends Sup {
  override type A >: (String,String) <: Product
  override def a: A = "s" -> "s"
}

trait Sub2 extends Sup {
  override type A >: (String,String) <: Serializable
  override def b: A = "s" -> "s"
}

object SS extends Sub1 with Sub2 {
  override type A = Product with Serializable
}

SS.a: Product with Serializable
SS.b: Product with Serializable
implicitly[SS.A =:= (Product with Serializable)]