案例类和隐式参数和模式匹配

Pet*_*itz 16 scala

我试图将隐式参数与案例类结合起来,但我陷入困境.

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 
}
Run Code Online (Sandbox Code Playgroud)

根据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)
}
Run Code Online (Sandbox Code Playgroud)

如何定义具有在创建时隐式提供的成员的案例类?

Ale*_*ise 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) => ...
}
Run Code Online (Sandbox Code Playgroud)


iai*_*ain 5

Alex的答案很聪明,但是我真的不喜欢_对象名称中的,我发现语法有点奇怪,并且记住下划线使模式匹配更加难以使用。(当然,这都是主观的,因此您的感觉可能会有所不同)。

解决这个问题的第一种方法是将隐式参数移至apply伴随对象中的方法。

case class A(i: Int, b: Boolean)

object Foo {
  def apply(i: Int)(implicit b: Boolean): Foo = apply(a, b)
}
Run Code Online (Sandbox Code Playgroud)

但这导致

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)
             ^
Run Code Online (Sandbox Code Playgroud)

正如我的朋友Yuriy所建议的,我们可以通过添加一个额外的Unused隐式参数来解决此问题。

object A {
  implicit object Unused

  def apply(i: Int)(implicit b: Boolean, unused: Unused.type): A = apply(i, b)
}
Run Code Online (Sandbox Code Playgroud)

您选择哪种方法取决于您,我发现这种方法使客户代码看起来更自然。