简体   繁体   English

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

[英]In scala 2.13+ / 3.x, how can we address the diamond inheritance problem of abstract types?

Here is a simple example:这是一个简单的例子:

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

Obviously it will cause a compilation error, as both override type A are mutually exclusive.显然它会导致编译错误,因为两个override type A是互斥的。 This is counter-intuitive as Product & Serializable are commonly used together.这是违反直觉的,因为 Product 和 Serializable 通常一起使用。 Alternatively, I can define:或者,我可以定义:

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
}

This makes definition of a and b invalid, as type A hasn't been reified, in addition, the line override type A = Product with Serializable is clearly a boilerplate and can be inferred instead.这使得 a 和 b 的定义无效,因为类型 A 尚未具体化,此外,行override type A = Product with Serializable显然是一个样板,可以改为推断。

What is the correct way to define an abstract type that allows diamond mixin, while avoid the boilerplate to explicitly define it in every implementations?定义允许菱形混合的抽象类型同时避免样板在每个实现中显式定义它的正确方法是什么?

I guess you lost lower bounds.我猜你失去了下限。

"s" -> "s" has type (String, String) , which is a subtype of Product (and Serializable ) but not a subtype of A <: Product (or A <: Serializable ). "s" -> "s"具有类型(String, String) ,它是Product (和Serializable )的子类型,但不是A <: Product (或A <: Serializable )的子类型。

Try尝试

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)]

If you specify return type of Sub1#a , Sub2#b to be A (above they were inferred to be (String, String) ie return type was narrowed upon method overriding) then如果您将Sub1#aSub2#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)]

You can do even你甚至可以做

object SS extends Sub1 with Sub2 {
  override type A >: (String, String) <: Product with Serializable
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM