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
。如果有人决定将不是 B
的 A
传递给 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)
请注意,因为 B
是 A
的子类型,您还可以将 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
我在 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
。如果有人决定将不是 B
的 A
传递给 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)
请注意,因为 B
是 A
的子类型,您还可以将 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