Класс Case и неявные аргументы и сопоставление с образцом - PullRequest
16 голосов
/ 15 марта 2011

Я пытался объединить неявные аргументы с классами 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 это связано с созданным компилятором объектом экстрактора для классов дел: Мой неявный Boolean не является членом результирующего класса дел, поэтому он должен быть во втором (неявном) аргументе list (к сожалению, я не могу найти в методе применения объекта-компаньона):

Определение класса дела 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)
}

Как я могу определить класс дел с членами, которые неявно предоставляются во время создания?

Ответы [ 2 ]

18 голосов
/ 15 марта 2011

Вы можете определить класс 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) => ...
}
5 голосов
/ 17 мая 2016

Ответ Алекса умный, однако мне не очень нравится _ в названии объекта, я нахожу синтаксис немного странным, и запоминание подчеркивания делает сопоставление с образцом более трудным для использования. (Конечно, это все субъективно, поэтому ваши чувства могут отличаться).

Моим первым подходом к решению этой проблемы было перемещение неявных параметров в метод 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)
}

Какой подход вы выберете, зависит от вас, я считаю, что этот подход позволяет моему клиентскому коду выглядеть более естественным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...