我们说我有以下特点
trait Named {
def name: String
}
和以下代数数据类型
sealed trait Animal extends Named
case object Dog extends Animal {
override val name: String = "dog man"
}
case object Cat extends Animal {
override val name: String = "cat man"
}
case object Owl extends Animal {
override val name: String = "I am an owl left in the dark"
}
现在,我可以使用以下方法将string的实例反序列化到我的Animal ADT中。
object Animal {
def apply(name: String): Animal = name match {
case Dog.name => Dog
case Cat.name => Cat
}
}
@oxbow_lakes在answer结束时提到:
无法从持久值中轻松实例化。这也是事实,但是, 除了巨大的枚举(例如,所有货币), 这并没有带来巨大的开销。
我发现当你添加一个新值时,它需要显式地添加到反序列化代码中,因为它容易出错(我认为编译器会警告我一个详尽的匹配,但看看{上面的{1}}和Owl
方法 - 没有发出警告......)
有没有更好的方法? (如果没有标准的scala工具集,第三方工具集?)
答案 0 :(得分:4)
enumeratum
库已解决此问题:
https://github.com/lloydmeta/enumeratum
您的代码可以这样写:
import enumeratum._
import enumeratum.EnumEntry.Lowercase
sealed trait Animal extends EnumEntry with Lowercase
object Animal extends Enum[Animal] {
val values = findValues
case object Dog extends Animal
case object Cat extends Animal
case object Owl extends Animal
}
val dogName = Animal.Dog.entryName
val dog = Animal.withNameInsensitive(dogName)
答案 1 :(得分:3)
您可以尝试的一件事是使用反射来获取扩展Animal
的一组类型,然后使用它来创建Map[String,Animal]
使用name
来查找对象值,然后使用Animal.apply
函数中的地图。
有关获取Animal
子类的详细信息,请参阅this question。