我试图将隐式参数与案例类结合起来,但我陷入了困境。
case class C(i: Int)(implicit b: Boolean)
val c1 = C(1)(true)
implicit val b = true
val c2 = C(2)
c1 match {
case C(i)(b) => // doesn´t work
case C(i,b) => // doesn´t work
case C(i) => // works, but wanted: if (b) i else 0
}
根据Scala语言规范,由于编译器为case类生成了提取器对象:我的隐式Boolean
不是结果case类的成员,所以它必须在第二个(隐式) )参数列表(遗憾的是,我在伴随对象的apply方法中找不到):
具有类型参数
c[tps](ps1 ). . .(psn)
和值的tps
的案例类定义 参数ps
隐式生成一个定义为的提取器对象(第8.1.8节) 如下:
object c {
def apply[tps](ps1 ). . .(psn): c[tps] = new c[Ts](xs1 ). . .(xsn)
def unapply[tps](x: c[tps]) =
if (x eq null) scala.None
else scala.Some(x.xs11, . . . , x.xs1k)
}
如何定义具有在创建时隐式提供的成员的案例类?
答案 0 :(得分:18)
您可以使用隐式参数定义案例类,但正如您所发现的,它们不可用于模式匹配。你总是可以编写自己的提取器:
case class C(i: Int)(implicit val b: Boolean)
// You can't call this C because that seat is taken (can't overload the default unapply)
object C_ {
// In order to be able to select `b` here,
// it needs to be declared as "implicit *val* b: Boolean"
def unapply(in: C) = Some((in.i, in.b))
}
c1 match {
case C_(i, b) => ...
}
答案 1 :(得分:5)
亚历克斯的答案很聪明,但是我不太喜欢对象名称中的_
,我发现语法有点奇怪并且记住下划线使得模式匹配更难以使用。 (当然这都是主观的,所以你的感受可能会有所不同)。
我处理这个问题的第一种方法是将隐式参数移动到配套对象中的apply
方法。
case class A(i: Int, b: Boolean)
object Foo {
def apply(i: Int)(implicit b: Boolean): Foo = apply(a, b)
}
但这会导致
Error:(21, 14) double definition:
method apply:(i: Int, b: Boolean)com.workday.cloud.master.package.A and
method apply:(i: Int)(implicit b: Boolean)com.workday.cloud.master.package.A at line 24
have same type after erasure: (i: Int, b: Boolean)com.workday.cloud.master.package.A
case class A(i: Int, b: Boolean)
^
正如我的朋友Yuriy建议的那样,我们可以通过添加额外的Unused
隐式参数来解决此问题。
object A {
implicit object Unused
def apply(i: Int)(implicit b: Boolean, unused: Unused.type): A = apply(i, b)
}
您选择哪种方法取决于您,我发现这种方法使我的客户端代码看起来更自然。