Is there a way to implement a hierarchical enumeration in scala?
我正在一个项目中,我需要在其中标记接收到的消息的类型。消息可能来自不同的来源,但是所有这些来源都会生成具有相同概念类型(因此,具有相同含义)但以不同方式编写的消息。
例如从source1我可以收到
来源1:
1 2 3 4 5 | { "message_type":"typeA", "value": 3 ... } |
要么
1 2 3 4 5 | { "message_type":"typeB", "value": 3 ... } |
而且从source2我也可以收到
来源2:
1 2 3 4 5 | { "message_type":"A", "value": 5 ... } |
要么
1 2 3 4 5 | { "message_type":"B", "value": 2 ... } |
我想最大程度地重复使用代码,因此尝试了此解决方案。
我创建的第一个scala文件是一个特征:
然后我在两个目标文件中实现了它:
1 2 3 4 5 6 7 |
所以现在我想要的是在不知道源类型的情况下检查消息的类型,如下所示:
1 2 3 4 5 6 |
但是,如果我编写此代码,IDE(IntelliJ)会以红色突出显示该参数,但不会提供有关该错误的信息。看来我只能使用Source1MessageType或Source2MessageType作为参数类型。
我认为错误是因为Scala不会将特征视为枚举,所以我无法访问该枚举的值。
您对此有什么解决方案吗?
是的,您可以进行层次枚举。因此,通常我建议不要使用
https://medium.com/@yuriigorbylov/scala-enumerations-hell-5bdba2c1216
最惯用的方法是利用类似以下特征的密封特征:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | sealed trait MessageType{ def value:String } sealed trait MessageType1 extends MessageType final case object TypeA extends MessageType1{ override def value:String ="typeA" } final case object TypeB extends MessageType1{ override def value:String ="typeB" } sealed trait MessageType2 extends MessageType final case object A extends MessageType2{ override def value:String ="A" } final case object B extends MessageType2{ override def value:String ="B" } |
请注意,所有这些定义都必须位于同一文件中。现在这行得通,因为
这意味着在给定
这使您可以在模式匹配等方面对枚举进行详尽的检查。
如果" A"和" typeA"是同一消息类型的名称,那么当您读入数据时,您需要进行处理。这意味着您在枚举中不需要任何嵌套。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | trait MessageType case object MessageTypeA extends MessageType case object MessageTypeB extends MessageType object MessageType { def apply(s: String): MessageType = s match { case"A" |"typeA" => MessageTypeA case"B" |"typeB" => MessageTypeB case _ => throw BadMessageType } } case class Message(msgType: MessageType, value: Int) |
您可以使用
如果需要保留生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | trait MessageType { def origin: String } case class MessageTypeA(origin: String) extends MessageType case class MessageTypeB(origin: String) extends MessageType object MessageType { def apply(s: String): MessageType = s match { case"A" |"typeA" => MessageTypeA(s) case"B" |"typeB" => MessageTypeB(s) case _ => throw BadMessageType } } |