2010-08-04 83 views
10

我有一個scala中的枚舉映射到JPA中的字符串。爲了更舒適的編碼,我定義了它們之間的隱式轉換。所以我現在可以定義值val person.role = "User", - person.role是枚舉類型一個字符串,所以有轉換。但是,當我試圖比較這兩個時,我總是會錯誤的,因爲def equals (arg0: Any) : Boolean需要Any,所以沒有任何轉換觸發。我需要一些明確的轉換,但我的計劃是能夠省略,你認爲最好的做法|這裏最新的解決方案?比較字符串和枚舉

+0

你是基於'Enumeration'和'Value'這個映射嗎? – Thomas 2010-08-04 16:48:35

+0

@Thomas是的我正在使用scala的'scala.Enumeration'和'scala.Enumeration.Value' – coubeatczech 2010-08-04 17:00:19

+0

什麼是比較的上下文/用例?模式匹配可能會提供更好的解決方案,但這取決於您想要完成的工作。 – 2010-08-04 18:51:07

回答

16

您的Enumeration中的Value("User")的類型爲Val。我相信它的執行equals不會比較值的字符串名稱。我認爲這樣做的一個重要方式是創建您自己的EnumerationVal,以便它在名稱匹配時返回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方法實施某種擴展,這很棘手。

13

擴大在托馬斯的回答,如果您使用的是比較分支,使用模式匹配可能更合適:

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 
    ... 
}