Сравнение строк и перечислений

У меня есть перечисление в scala, сопоставленное строкам в JPA. Для более удобного кодирования я определял неявные преобразования между ними. Поэтому теперь я могу определить значение val person.role = "User", - person.role - это тип перечисления "User" a String, чтобы преобразование. Но когда я пытаюсь сравнить эти два, я всегда получаю false, потому что def equals (arg0: Any) : Boolean занимает Any, поэтому никакого преобразования не запускается. Мне нужно некоторое явное преобразование, но мой план состоял в том, чтобы упустить это, как вы думаете, это лучшая практика | здесь самое лучшее решение?

Ответ 1

Value("User") Value("User") имеет тип Val. И я считаю, что реализация equals не сравнивает имя строки значения. Я думаю, что один тяжелый способ сделать это - создать свои собственные Enumeration и Val, чтобы он возвращал true, если имя соответствует.

Но в моем коде используется не JPA, я всегда конвертирую строку в MyEnumeration.Value. Это легко с такими вещами, как:

 object E extends Enumeration { val User = Value("User") }

 scala> val a = E.withName("User")
 a: E.Value = User

Обратите внимание, что при использовании withName, если строка не соответствует ни одному имени в перечислении, вы получаете исключение.

Затем всегда используйте поля перечисления в своих сравнениях:

scala> a == E.User
res9: Boolean = true

Если JPA возвращает только строку, и ее нет. Тогда я думаю, что лучший вариант - либо преобразовать значение в строку и строку соответствия в строку, либо обновить строку до Val и сравнить Val. Смешивание этих типов не будет работать для сравнения, если вы не реализуете какое-то расширение для метода equals, и это сложно.

Ответ 2

Развернувшись на ответ Томаса, если вы используете сравнение с веткой, использование шаблонов может быть более подходящим:

object Role extends Enumeration {
   val User = MyValue("User")
   val Admin = MyValue("Admin")

   def MyValue(name: String): Value with Matching = 
         new Val(nextId, name) with Matching

   // enables matching against all Role.Values
   def unapply(s: String): Option[Value] = 
      values.find(s == _.toString)

   trait Matching {
      // enables matching against a particular Role.Value
      def unapply(s: String): Boolean = 
            (s == toString)
   }
}

Затем вы можете использовать это следующим образом:

def allowAccess(role: String): Boolean = role match {
   case Role.Admin() => true
   case Role.User() => false
   case _ => throw ...
}

или

// str is a String
str match { 
   case Role(role) => // role is a Role.Value
   case Realm(realm) => // realm is a Realm.Value
   ...
}