【发布时间】:2016-10-25 12:13:40
【问题描述】:
假设我有一个 ADT 和类型类 Foo,如下所示:
sealed trait A
case class A1() extends A
case class A2() extends A
case class A3() extends A
trait Foo[X] { def foo(x: X): String; }
object Foo {
implicit val a1foo = new Foo[A1] { def foo(a1: A1) = "A1" }
implicit val a2foo = new Foo[A2] { def foo(a2: A2) = "A2" }
implicit val a3foo = new Foo[A3] { def foo(a3: A3) = "A3" }
}
现在我可以这样写Foo[A]:
implicit val afoo = new Foo[A] {
def foo(a: A) = a match {
case a1 : A1 => a1foo.foo(a1)
case a2 : A2 => a2foo.foo(a2)
case a3 : A3 => a3foo.foo(a3)
}
}
很遗憾,这段代码太boilerplaty。是否有可能自动摆脱所有样板文件并派生 Foo[A](可能使用shapeless)?
【问题讨论】:
-
implicit def fromA[A](a: A): Foo[A] = new Foo[A] { def foo(a: A) = a.getClass.getSimpleName }够用吗?它将编译Foo.fromA(A1).foo(A1)而不是Foo.fromA(A1).foo(A2)。 -
getClass.getSimpleName是运行时反射调用吗? -
是的,但我添加它是为了说明。你知道里面
fooA型。 -
@ipoteka 我没明白,抱歉。你能写更详细的答案吗?
-
Shapeless 确实可以用来解决问题。它需要编写比您在问题中列出的代码更多的代码,但它会在更大的代码库中减少很多样板。我写了a blog post about using Shapeless,这可能对您描述的场景有所帮助。对不起,无耻的插件。