Scala: универсальный парсер для значений перечисления

Я думал, что должна быть возможность написать общую функцию, которая работает для всех значений перечисления. Сначала я попробовал простой парсер, но мне это не удалось:

object Weekday extends Enumeration {
  type Weekday = Value

  val MONDAY = Value("MONDAY")
  val OTHER = Value("OTHER")

  implicit def valueToWeekday(v: Value): Weekday = v.asInstanceOf[Weekday]
  implicit def stringToWeekday(s: String): Weekday = Weekday.withName(s)
}

object Enumerations {
  import Weekday._
  println("Welcome to the Scala worksheet")

  def parseEnumeration[T <: Enumeration](s: String)(implicit ev: T): T#Value = {
    ev.withName(s)
  }

 val test = parseEnumeration[Weekday]("MONDAY")
}

Итак, как я могу написать универсальную функцию, принимающую тип перечисления в качестве параметра и возвращающую значение этого типа? Я немного запутался здесь с объектом и внутренним типом с тем же именем.


person Da Li    schedule 21.09.2015    source источник
comment
Несколько связано: stackoverflow.com/questions/21511656/ & stackoverflow.com/questions/14451152 /   -  person dskrvk    schedule 14.10.2016


Ответы (1)


Во-первых, ваш неявный метод valueToWeekday на самом деле ничего не делает, так как Weekday в этом контексте является просто псевдонимом для Value.

Во-вторых, ваш неявный метод stringToWeekday является рабочим, хотя и неуниверсальным преобразованием строки в ее значение перечисления.

Однако сделать stringToWeekday универсальным несложно. Вам просто нужно передать перечисление в функцию, как в parseEnumeration. Поскольку вы сделали свидетельство в parseEnumeration неявным, все, что вам нужно сделать, это поместить соответствующее неявное значение в контекст. Кроме того, вы можете передать свидетельство явно.

Таким образом, вы можете удалить эти неявные преобразования (и псевдоним типа, поскольку конфликт имен немного вводит в заблуждение).

object Weekday extends Enumeration {
  val Monday = Value("MONDAY")
  val Other = Value("OTHER")
}
  1. Неявный способ:

    def parseEnumeration[T <: Enumeration](s: String)(implicit ev: T): T#Value = ev.withName(s)
    
    implicit val evidence = Weekday
    val weekday = parseEnumeration("MONDAY") // results in the value Weekday.Monday
    
  2. Явный способ:

    def parseEnumeration[T <: Enumeration](s: String, enumeration: T): T#Value = enumeration.withName(s)
    
    val weekday = stringToEnumerationValue("MONDAY", Weekday) // results in the value Weekday.Monday
    

Третьим вариантом может быть использование ClassTag в качестве доказательства, которое компилятор помещает в контекст через общие параметры. Однако для фактического вызова метода withName требуется отражение, и я бы не рекомендовал идти по этому пути.

person Kulu Limpa    schedule 21.09.2015