我在我需要的标签接收到的消息的类型项目。消息可以来自不同的来源,但所有这些源产生具有相同的概念类型(因此,相同的含义),但用不同的方式的消息。
例如,从来源1,我可以接受
源1:
{
"message_type": "typeA",
"value": 3
...
}
要么
{
"message_type": "typeB",
"value": 3
...
}
而且从源2我可以接受
源2:
{
"message_type": "A",
"value": 5
...
}
要么
{
"message_type": "B",
"value": 2
...
}
我想最大限度的代码重用,所以我尝试这个解决方案。
我创建的第一个斯卡拉文件是一个特点:
trait MessageType extends Enumeration {
val TYPE_A: Value
val TYPE_B: Value
}
然后,我实现了它在两个目标文件:
object Source1MessageType extends MessageType{
override val TYPE_A: Value("typeA")
override val TYPE_B: Value("typeB")
object Source2MessageType extends MessageType{
override val TYPE_A: Value("A")
override val TYPE_B: Value("B")
所以现在我要的是检查消息的类型不知道源类型,如下所示:
def foo(type: MessageType.Value) {
type match{
case MessageType.TYPE_A => ...do A action...
case MessageType.TYPE_B => ...do B action...
}
}
但是,如果我写这篇文章的代码时,IDE(的IntelliJ)突出了红色的参数,但它给了我有关错误没有信息。好像我只能使用Source1MessageType或Source2MessageType作为参数类型。
我认为错误是因为Scala并不认为特质作为一个枚举,所以我不能访问枚举值。
你有任何解决方案?
是的,你可以做分层枚举。所以一般我会建议不要使用Enumeration
。下面是与为什么它是坏的文章
https://medium.com/@yuriigorbylov/scala-enumerations-hell-5bdba2c1216
最习惯的方式来做到这一点是通过利用密封特性是这样的:
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"
}
请注意,所有这些定义需要在同一个文件。现在这个工作,因为sealed
和final
告诉编译器,继承只能在该文件中出现。
这意味着,给定MessageType2
编译器的一个实例,知道它只能为对象A
或B
它不可能是别的(密封/最终因)
这使您可以枚举与全面性检查中模式匹配等。
如果“A”和“的typeA”是相同的消息类型的名称,那么你需要的时候,你在数据读取方面来处理这个问题。这意味着,你不需要在你的枚举任何嵌套。
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)
您可以创建MessageType(<string>)
消息类型,它将返回MessageTypeA
或适当MessageTypeB
。您可以使用正常的match
,以确定您有消息类型。
如果您需要保存生成的MessageType
原始字符串,那么你可以存储为抽象值在MessageType
特质,并创建相应的实例时,填写好:
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
}
}