Класс случая и неявные аргументы и соответствие шаблонов
Я попытался объединить неявные аргументы с классами case, но я застрял.
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: My implicit Boolean
не является членом результирующего класса case, поэтому он должен быть во втором (неявный ) список аргументов (к сожалению, я не могу найти в методе применения сопутствующего объекта):
Определение класса case 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)
}
Как я могу определить класс case с членами, которые неявно поставляются во время создания?
Ответы
Ответ 1
Вы можете определить класс case с неявными аргументами, но, как вы обнаружили, они недоступны для сопоставления шаблонов. Вы всегда можете написать свой собственный экстрактор:
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) => ...
}
Ответ 2
Ответ Alex умный, однако мне не очень нравится _
в имени объекта, я считаю, что синтаксис немного странный, и помните, что подчеркивание делает совпадение шаблонов более сложным в использовании. (Конечно, это все субъективно, поэтому ваши чувства могут меняться).
Мой первый подход к решению этого вопроса заключался в перемещении неявных параметров в метод 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)
^
Как предложил мой друг Юрий, мы можем исправить это, добавив дополнительный Unused
неявный параметр.
object A {
implicit object Unused
def apply(i: Int)(implicit b: Boolean, unused: Unused.type): A = apply(i, b)
}
Какой подход вы выбираете, зависит от вас, я нахожу, что этот подход позволяет моему клиенту выглядеть более естественным.