Scala - 类型类覆盖抽象方法

Scala - Typeclass overriding the abstract method

我在 scala 2.12 上遇到了一些困难:

我有以下层次结构:

trait A

case class B(format: String) extends A

trait Writer {
  def write(config: A): Unit
}


val writer = new Writer {
  override def write(config: A) = println("hi")
}

val w = B("console")
writer.write(w)

效果很好。但我想为 writer 提供一个替代实现:

val writer = new Writer {
  override def write(config: B) = println("hi")
}

但是我得到了object creation impossible, since method write in trait Writer of type (config: Playground.A)Unit is not defined

我假设因为 B 是 A,所以这应该可行。如何使用类型为 B 的配置覆盖 write,其中 B <: A

斯卡斯蒂:https://scastie.scala-lang.org/QBaiiDP4Sj2lptUjrWLJYw

编辑:------------------------------------ ----------------------

根据一些输入,我将实现更改为:

sealed trait A

case class B(format: String) extends A

trait Writer[+T] {
  def write[S >: T](config: S): Unit
}


val writer: Writer[A] = new Writer[B] {
  override def write[B](config: B) = println("hi")
}


val b = B("console")
writer.write(b)

有效。

但是如果我修改它以访问 config 中的变量,它会中断:

sealed trait A

case class B(format: String) extends A

trait Writer[+T] {
  def write[S >: T](config: S): Unit
}


val writer: Writer[A] = new Writer[B] {
  override def write[B](config: B) = println(config.format)
}


val b = B("console")
writer.write(b)

value format is not a member of type parameter B

https://scastie.scala-lang.org/Xj2rKbbiTmG7raZgQZYfHA

感谢输入。

它不起作用,因为 Writer 声明其 write 方法将接受任意 A。如果有人决定将不是 BA 传递给 writer.write 怎么办?然后它就不会工作,所以编译器会阻止你这样做。

您已经非常接近最新版本了。正如 Matthias Berndt 指出的那样,write 方法声明了一个 new 类型参数,但应该使用在特征上声明的那个。另外,类型参数应该是contravariant.

此代码编译并打印 console:

sealed trait A

case class B(format: String) extends A

trait Writer[-T <: A] {
  def write(config: T): Unit
}


val writer: Writer[B] = new Writer[B] {
  override def write(config: B) = println(config.format)
}


val b = B("console")
writer.write(b)

请注意,因为 BA 的子类型,您还可以将 Writer[A]B 的实例一起使用。因为 Writer 是逆变的,所以可以将 Writer[A] 类型的值赋给 Writer[B] 类型的变量:

val aWriter: Writer[B] = new Writer[A]  {
  override def write(config: A) = println(s"Got A: $config")
}

aWriter.write(b) // prints "Got A: B(console)"

你不能做相反的事情(将 Writer[B] 值分配给 Writer[A] 变量)因为 Writer[A] 可以接受任何类型的值 A,而 Writer[B] 只能接受 B.

类型的值

https://scastie.scala-lang.org/TimMoore/bd5E1p99TLCDVfMbElKqFg/8