【发布时间】:2018-01-20 17:17:37
【问题描述】:
我正在使用两个 Scala 库,它们都依赖隐式参数来为案例类提供编解码器/编组器(有问题的库是 msgpack4s 和 op-rabbit)。一个简化的例子如下:
sealed abstract trait Event
case class SomeEvent(msg: String) extends Event
case class OtherEvent(code: String) extends Event
// Assume library1 needs Show and library2 needs Printer
trait Show[A] { def show(a: A): String }
trait Printer[A] { def printIt(a: A): Unit }
object ShowInstances {
implicit val showSomeEvent = new Show[SomeEvent] {
override def show(a: SomeEvent) =
s"SomeEvent: ${a.msg}"
}
implicit val showOtherEvent = new Show[OtherEvent] {
override def show(a: OtherEvent) =
s"OtherEvent: ${a.code}"
}
}
一个库的打印机可以是通用的,前提是另一个库可用的隐式显示:
object PrinterInstances {
implicit def somePrinter[A: Show]: Printer[A] = new Printer[A] {
override def printIt(a: A): Unit =
println(implicitly[Show[A]].show(a))
}
}
我想提供一个抽象底层库细节的 API - 调用者应该只需要传递案例类,在 API 实现内部应该调用相关的隐式。
object EventHandler {
private def printEvent[A <: Event](a: A)(implicit printer: Printer[A]): Unit = {
print("Handling event: ")
printer.printIt(a)
}
def handle(a: Event): Unit = {
import ShowInstances._
import PrinterInstances._
// I'd like to do this:
//EventHandler.printEvent(a)
// but I have to do this
a match {
case s: SomeEvent => EventHandler.printEvent(s)
case o: OtherEvent => EventHandler.printEvent(o)
}
}
}
EventHandler.handle() 方法中的 cmets 表明了我的问题 - 有没有办法让编译器为我选择正确的隐式?
我怀疑答案是否定的,因为在编译时编译器不知道 Event handle() 的 哪个 子类将接收,但我想看看是否还有其他方法。在我的实际代码中,我控制 & 可以更改 PrinterInstances 代码,但我无法更改 printEvent 方法的签名(由其中一个库提供)
*编辑:我认为这与Provide implicits for all subtypes of sealed type 相同。那里的答案将近2年了,我想知道它是否仍然是最好的方法?
【问题讨论】:
-
蛮力方法:用单个
implicit def somePrinter: Printer[Event]替换多态implicit def somePrinter并在内部处理案例。 -
我们的情况并不像Provide implicits for all subtypes of sealed type那么绝望。特别是,我们不需要 'shapeless' 的原始力量 :-)
标签: scala traits implicits subtype