Неявные преобразования в контексте конструктора класса (case)

Я хотел бы иметь конструкторы класса ---- +: = 0 =: + ---- класса case-компаньонов для выполнения неявных преобразований для меня, но не могу понять как это сделать Я искал все, и самый близкий ответ, который я мог найти, был для этот вопрос (ниже я объясню, почему это не то, что я ищу).

У меня есть класс case, который выглядит примерно так:

apply

Я использую контейнер для подсчета случаев, когда применяются определенные условия, поэтому я бы хотел, чтобы конструктор автоматически преобразовывал логические параметры в long (case class Container(a: Long, b: Long, c: Long) ).

Реальный класс case, конечно, имеет много параметров, поэтому было бы утомительно и ужасно повторять создание собственного объекта-компаньона и перегрузку if (boolean) 1L else 0L принять параметры apply. Кроме того, что-то вроде приведенного ниже кода не является идеальным (если оно каким-то образом правильно реализовано), так как принимает только логические аргументы:

Boolean

Я попытался добавить неявное преобразование в объект-компаньон (ниже), надеясь, что оно будет автоматически использоваться в object Container { def apply(args: Boolean*) = { // doesn't REALLY work since number of arguments not enforced Container(args map { if (_) 1L else 0L } toArray: _*) } } val c1 = Container(1, 0, 1) // works val c2 = Container(true, false, true) // might be workable if done correctly val c3 = Container(true, 0, 1) // won't work , но это Похоже, что на самом деле это не помещает неявное преобразование в пространство имен кода, к которому применяются вызовы.

Container.apply

Я могу заставить все работать, используя этот хакерский обходной путь:

object Container {
  implicit def booleanToLong(x: Boolean): Long = if (x) 1L else 0L
}

Самая большая проблема заключается в том, что мне нужно импортировать { import Container.booleanToLong // all of these now work val c1 = Container(1, 0, 1) val c2 = Container(true, false, true) val c3 = Container(true, 0, 1) // works!!! } в код, который хочет создать booleanToLong и, таким образом, для безопасности должен поместить его в собственный блок (Container обычно нежелательно).

Наконец, решение использовать неявный параметр, который сам включает в себя неявное преобразование, не работает, потому что это потребовало бы явного переопределения booleanToLong, побеждая цель не повторять длинный список параметров и маршалинг типов.

Есть ли способ сделать это так, чтобы я получал неявные преобразования бесплатно каждый раз, когда я делаю apply, но не иначе? Или это невозможно из-за каких-то технических ограничений?

7 голосов | спросил Ben Sidhom 26 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 26 Sep 2013 04:54:01 +0400 2013, 04:54:01

1 ответ


0

Вы можете использовать своего рода вариант шаблона магнита чтобы сделать это немного безопаснее. Сначала для класса типов:

trait ToLong[A] {
  def apply(a: A): Long
}

implicit object longToLong extends ToLong[Long] {
  def apply(l: Long) = l
}

implicit object booleanToLong extends ToLong[Boolean] {
  def apply(b: Boolean) = if (b) 1L else 0L
}

А теперь нам просто нужен один дополнительный конструктор:

case class Container(a: Long, b: Long, c: Long)

object Container {
  def apply[A: ToLong, B: ToLong, C: ToLong](a: A, b: B, c: C) = new Container(
    implicitly[ToLong[A]].apply(a),
    implicitly[ToLong[B]].apply(b),
    implicitly[ToLong[C]].apply(c)
  )
}

И мы можем написать следующее:

val c1 = Container(1, 0, 1)
val c2 = Container(true, false, true)
val c3 = Container(true, 0L, 1L)

Без необходимости вводить довольно страшное общее преобразование из Boolean в Long.

ответил Travis Brown 26 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 26 Sep 2013 06:45:38 +0400 2013, 06:45:38

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132