scala ADT通过密封特征 - 有没有办法以通用方式从字符串反序列化

时间:2017-04-27 13:05:02

标签: scala deserialization algebraic-data-types

我们说我有以下特点

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工具集,第三方工具集?)

2 个答案:

答案 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