scala和java枚举之间的差异

我在SO上读到了一个答案,其中有人说scala枚举是无用的 ,如果你真的需要,你应该只使用java枚举。

虽然我之前使用过java枚举,但我不能说我完全理解它们,因为我在日常工作中不用java编码。

有人可以解释scala和java枚举之间的区别,以及scala枚举中的缺点究竟在哪里?

Scala枚举的主要缺点是难以向它们添加方法和字段。 在Java中,将枚举用作具有固定数量实例的类是非常简单的(例如,为什么它们是实现单例的好选择)。

然而,在Scala中,Enums只是一组可能的值; 向它们添加方法和字段是一个更加hacky的过程。 因此,如果你想要从枚举中获得超出微不足道的行为,Java枚举是一个更方便的工具。

例如,Java枚举可能如下所示:

public enum Month{ january(31), february(28), ... december(31); public final int daysInMonth; Month(int daysInMonth){ this.daysInMonth = daysInMonth; } } 

但是,在Scala中,您必须这样做:

 object Month extends Enumeration{ protected case class Val(val daysInMonth:Integer) extends super.Val{} implicit def valueToMonth(x:Value) = x.asInstanceOf[Val] val january = Val(31) val february = Val(28) .... } 

这在一个像这样的简单示例中看起来并不坏,但它确实添加了一些令人困惑的语法,并增加了另一个类的开销,需要隐式转换为enum的大多数用法。

我看到Java枚举的主要优点是你准确地写出了你的意思; 一个枚举,上面有一些方法和字段。 在斯卡拉,你写的不是你的意思; 你需要创建一个枚举,它包含一个具有你想要的方法和字段的类,并且还定义了从该类到枚举的转换。 表达同样的想法是一种不那么惯用的方式。

正如评论中指出的那样,Scala确实提供了Case Classes ,它可以在很多情况下用作枚举的替代方法,并且具有更清晰的语法。 但是仍然存在一些情况,其中Case Classes是不够的(例如当你想迭代所有值时),所以常规枚举仍然有它们的位置。 更正 :使用宏确实可以迭代Case Classes,但这样做有其自身增加的复杂性,而枚举(在Scala和Java中)更容易迭代。

Scala的Enumeration的主要优点是语法的规律性。

如果要向枚举元素添加行为,只需扩展其Val类。

Odersky喜欢将它们作为最简单的用例命名为int-valued常量。 他刚刚在邮件列表上承诺,第一次提供更好的支持即将到来。

但我最近 使用它们来替换字符串列表,因为值集是有点设置的,比查找字符串组更好。

代替

 val stuff = List("foo", "bar", "baz") object stuff extends Enumeration { val foo, bar, baz = Value } 

要么

 scala> object stuff extends Enumeration { val foo, bar, baz = Value } defined object stuff scala> val junk = new Enumeration { val foo, bar, baz = Value } junk: Enumeration{val foo: this.Value; val bar: this.Value; val baz: this.Value} = 1 scala> stuff.values contains junk.foo :10: error: type mismatch; found : junk.Value required: stuff.Value stuff.values contains junk.foo ^ 

行为:

 scala> trait Alias { def alias: String } defined trait Alias scala> object aliased extends Enumeration { | class Aliased extends Val with Alias { | def alias = toString.permutations.drop(1).next } | val foo, bar, baz = new Aliased } defined object aliased scala> abstract class X { type D <: Enumeration | def f(x: D#Value) = x match { case a: Alias => a.alias | case _ => x.toString } } defined class X scala> class Y extends X { type D = aliased.type } defined class Y scala> new Y().f(aliased.bar) res1: String = bra scala> new Y().f(stuff.foo) :13: error: type mismatch; found : stuff.Value required: aliased.Value new Y().f(stuff.foo) ^ scala> new X { type D = junk.type }.f(junk.foo) warning: there was one feature warning; re-run with -feature for details res4: String = foo 

ValueSet有点设置:

 scala> stuff.values contains aliased.bar :11: error: type mismatch; found : aliased.Aliased required: stuff.Value stuff.values contains aliased.bar ^ scala> stuff.foo + aliased.bar :11: error: type mismatch; found : aliased.Aliased required: stuff.Value stuff.foo + aliased.bar ^ scala> stuff.foo + stuff.bar res8: stuff.ValueSet = stuff.ValueSet(foo, bar) 

其他似乎在今天的Scala中工作的东西:

 scala> def f[E <: Enumeration](e: E)(v: e.Value) = e.ValueSet.empty + v f: [E <: Enumeration](e: E)(v: e.Value)e.ValueSet scala> f(stuff)(stuff.foo) res14: stuff.ValueSet = stuff.ValueSet(foo) scala> def g[E <: Enumeration](e: E)(a: Any) = a match { case _: e.Value => true case _ => false } g: [E <: Enumeration](e: E)(a: Any)Boolean scala> g(stuff)(stuff.foo) res15: Boolean = true scala> g(stuff)(junk.foo) // checking outer pointers warning: there was one feature warning; re-run with -feature for details res16: Boolean = false scala> g(stuff)(aliased.foo) res17: Boolean = false 

看起来Scala 对Java枚举并不完全友好 :

 scala> Thread.State.NEW.ordinal [snip] scala.reflect.internal.FatalError: Unknown type: (NEW),  [class scala.reflect.internal.Types$UniqueConstantType, class scala.reflect.internal.Types$NoType$] TypeRef? false while compiling:  during phase: icode library version: version 2.11.2 compiler version: version 2.11.2 reconstructed args: last tree to typer: Apply(method ordinal) tree position: line 8 of  tree tpe: Int symbol: final method ordinal in class Enum symbol definition: final def ordinal(): Int (a MethodSymbol) symbol package: java.lang symbol owners: method ordinal -> class Enum call site: constructor $read$$iw$$iw in package $line4