Scala - 枚举与案例类

时间:2012-11-12 12:12:21

标签: scala enums akka actor case-class

我创建了一个名为LogActor的akka​​ actor。 LogActors的receive方法处理来自其他actor的消息并将它们记录到指定的日志级别。

我可以通过两种方式区分不同的等级。第一个:

import LogLevel._
object LogLevel extends Enumeration {
    type LogLevel = Value
    val Error, Warning, Info, Debug = Value
}
case class LogMessage(level : LogLevel, msg : String) 

第二个:(编辑

abstract class LogMessage(msg : String)
case class LogMessageError(msg : String) extends LogMessage(msg)
case class LogMessageWarning(msg : String) extends LogMessage(msg)
case class LogMessageInfo(msg : String) extends LogMessage(msg)
case class LogMessageDebug(msg : String) extends LogMessage(msg)

哪种方式更有效?是否需要更少的时间来匹配案例类或匹配枚举值?

(我读过this个问题,但没有任何答案提到运行时问题)

3 个答案:

答案 0 :(得分:26)

我完全同意Alexey和Dennis在这种情况下的性能不应该打扰你,因为它更多的是编译器优化的问题,而不是开发人员,我无法想象性能差异会变得明显的情况。

你应该打扰你的是代码的一致性,从这个意义上说,你应该根据你的第一个例子中正确描述的enum是否要坚持旧的java-ish方法或者最近流行代数数据类型(ADT)模式。后者你试图在你的第二个例子中代表,但有一些错误。

以下是如何正确解决ADT模式的问题。

ADT解决方案#1

// 1. marked `sealed` to make pattern matching exhaustive
// 2. used a trait to avoid double storage of msg` and 
//    make the inheritance easier
sealed trait LogMessage { def msg : String }
// A better solution for isolation than names like "LogMessageError".
// Allows you to either address the members with a namespace like 
// "LogMessage.Error" or do "import LogMessage._" and address them 
// directly
object LogMessage { 
  case class Error (msg : String) extends LogMessage
  case class Warning (msg : String) extends LogMessage
  case class Info (msg : String) extends LogMessage
  case class Debug (msg : String) extends LogMessage
}

ADT解决方案#2

很抱歉可能会弄乱你的脑袋,但值得注意的是,对于类似的情况也存在替代的ADT方法,这类似于你用枚举的方式。

sealed trait LogLevel 
object LogLevel {
  case object Error extends LogLevel
  case object Warning extends LogLevel
  case object Info extends LogLevel
  case object Debug extends LogLevel
}
case class LogMessage ( level : LogLevel, msg : String )

答案 1 :(得分:8)

“不要过早优化”适用。我不相信它们之间的差异可能很重要,相比之下,您花费时间将消息传递给您的演员或实际记录它们。但我希望最好的表现是创建一个Java enum(可以很容易地从Scala访问和使用)来记录级别而不是Scala Enumeration

答案 2 :(得分:0)

记录器最常见的操作之一是将当前日志记录级别与消息级别进行比较,并使用枚举将其免费获取,而使用案例类进行设置则会有些麻烦。我同意@AlexeyRomanov:匹配不应该成为瓶颈。

编辑:性能方面,与案例类匹配将在字节码中使用instanceof,而对于枚举scala编译器生成的代码,我尝试的所有反编译器都无法处理。它好像在使用equals。因此技术上的枚举可能会更快,但实际上性能没有差异。