在Scala中,何时使用案例类(或案例对象)与扩展枚举有什么最佳实践指南吗?
它们似乎提供了一些相同的好处。
在Scala中,何时使用案例类(或案例对象)与扩展枚举有什么最佳实践指南吗?
它们似乎提供了一些相同的好处。
当前回答
我在这里有一个简单的库,允许你使用密封的trait /类作为枚举值,而不必维护自己的值列表。它依赖于一个简单的宏,不依赖于有bug的knownDirectSubclasses。
https://github.com/lloydmeta/enumeratum
其他回答
如果你想要维护与其他JVM语言(如Java)的互操作性,那么最好的选择是编写Java枚举。这些功能在Scala和Java代码中都可以透明地工作,这在Scala中是做不到的。枚举或case对象。如果可以避免的话,让我们不要为GitHub上的每个新爱好项目都创建一个新的枚举库!
一个很大的区别是枚举支持从某个名称String实例化它们。例如:
object Currency extends Enumeration {
val GBP = Value("GBP")
val EUR = Value("EUR") //etc.
}
然后你可以这样做:
val ccy = Currency.withName("EUR")
这在希望持久化枚举(例如,到数据库)或从驻留在文件中的数据创建枚举时非常有用。然而,我发现在Scala中枚举通常有点笨拙,给人一种笨拙的附加组件的感觉,所以我现在倾向于使用case对象。case对象比enum更灵活:
sealed trait Currency { def name: String }
case object EUR extends Currency { val name = "EUR" } //etc.
case class UnknownCurrency(name: String) extends Currency
所以现在我的优势是……
trade.ccy match {
case EUR =>
case UnknownCurrency(code) =>
}
正如@ chaotic3equilibrium所指出的(为了便于阅读,做了一些更正):
关于“UnknownCurrency(code)”模式,除了“破坏”currency类型的封闭集性质外,还有其他方法可以处理找不到货币代码字符串的问题。类型为Currency的UnknownCurrency现在可以潜入API的其他部分。 建议将这种情况推到枚举之外,并让客户端处理Option[Currency]类型,这将清楚地表明确实存在匹配问题,并“鼓励”API的用户自己进行排序。
为了跟进这里的其他答案,case对象相对于Enumerations的主要缺点是:
不能遍历“枚举”的所有实例。这当然是事实,但我发现在实践中很少需要这样做。 不容易从持久化值实例化。这也是正确的,但是,除了在大量枚举的情况下(例如,所有货币),这并不会带来巨大的开销。
2017年3月更新:正如Anthony Accioly所评论的,scala。枚举/枚举PR已关闭。
Dotty (Scala的下一代编译器)将占据主导地位,尽管Dotty发行于1970年,Martin Odersky的PR发行于1958年。
注意:现在(2016年8月,6年多之后)有一个移除scala的提案。编号:PR 5352
scala抨击。枚举,添加@enum注释 的语法
@enum
class Toggle {
ON
OFF
}
是一个可能的实现示例,目的是也支持符合某些限制(没有嵌套,递归或变化的构造函数参数)的adt,例如:
@enum
sealed trait Toggle
case object ON extends Toggle
case object OFF extends Toggle
Deprecates the unmitigated disaster that is scala.Enumeration. Advantages of @enum over scala.Enumeration: Actually works Java interop No erasure issues No confusing mini-DSL to learn when defining enumerations Disadvantages: None. This addresses the issue of not being able to have one codebase that supports Scala-JVM, Scala.js and Scala-Native (Java source code not supported on Scala.js/Scala-Native, Scala source code not able to define enums that are accepted by existing APIs on Scala-JVM).
我认为与枚举相比,使用case类的最大优点是可以使用类型类模式,也就是ad-hoc polymorphysm。不需要像这样匹配枚举:
someEnum match {
ENUMA => makeThis()
ENUMB => makeThat()
}
相反,你会看到如下内容:
def someCode[SomeCaseClass](implicit val maker: Maker[SomeCaseClass]){
maker.make()
}
implicit val makerA = new Maker[CaseClassA]{
def make() = ...
}
implicit val makerB = new Maker[CaseClassB]{
def make() = ...
}
当您需要遍历或过滤所有实例时,case类相对于枚举的另一个缺点。这是枚举(以及Java枚举)的内置功能,而case类并不自动支持这种功能。
换句话说:“没有简单的方法可以获得包含case类的全部枚举值集的列表”。