2014-08-29 117 views
5

我讀an answer on SO where someone said that scala enumerations are useless,如果你真的需要,你應該只使用java枚舉。scala和java枚舉之間的區別

雖然我之前使用過java枚舉,但我不能說我完全理解它們,因爲我在日常工作中不用java代碼。

有人可以解釋scala和java枚舉之間的區別,以及scala枚舉中的缺點究竟在哪裏?

+0

Scala的枚舉是不是落後。 http://stackoverflow.com/questions/21537148/scala-java-enumerations它只是不如斯卡拉的案例類/對象。 – Naetmul 2014-08-29 15:35:29

回答

8

Scala枚舉的主要弱點是難以向它們添加方法和字段。在Java中,使用枚舉作爲具有固定數量實例的Class(例如,爲什麼它們是實現單例的理想選擇)是微不足道的。

然而,在斯卡拉枚舉只是一組可能的值;向他們添加方法和領域是一個更加棘手的過程。所以如果你想要從枚舉中除了微不足道的行爲之外,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枚舉中看到的主要優點是,你完全可以寫出你的意思;一個枚舉,其上有一些方法和字段。在斯卡拉,你寫的東西不是你的意思;您需要創建一個枚舉,其中包含一個具有所需方法和字段的類,並且還定義從該類到枚舉的轉換。這是表達同樣想法的一種不那麼習慣的方式。

正如所指出的in the comments,斯卡拉確實提供Case Classes,它可以在許多情況下作爲枚舉的替代品,並且有更清晰的語法。但是在某些情況下,Case Classes還不夠(例如當你想迭代所有值時),所以常規的枚舉仍然有它們的位置。 更正:使用宏確實可以迭代Case Classes,但這樣做有其自身增加的複雜性,而枚舉(在Scala和Java中)則更容易迭代。

+1

值得注意的是,第三種解決方案是使用大小寫對象,[在這裏討論](http://stackoverflow.com/questions/1898932/case-classes-vs-enumerations-in-scala)。 – 2014-08-29 17:23:41

+0

和密碼特徵的迭代可能與宏 - http://stackoverflow.com/questions/13671734/iteration-over-a-sealed-trait-in-scala – Gavin 2014-08-29 20:03:56

3

Scala的Enumeration的主要優點是語法的規律性。

如果要將行爲添加到枚舉的元素,只需擴展它的Val類即可。

Odersky將它們作爲最簡單的用例命名爲int值常量。他剛剛在郵件列表上承諾,第一次,改善的支持即將到來。

但我recentlyused他們替換字符串的列表,因爲值的集合是一個位集,比一組查詢字符串更好。

而不是

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 
<console>: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) 
<console>: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 
<console>:11: error: type mismatch; 
found : aliased.Aliased 
required: stuff.Value 
       stuff.values contains aliased.bar 
              ^

scala> stuff.foo + aliased.bar 
<console>: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 

not entirely friendly to Java enums

scala> Thread.State.NEW.ordinal 
[snip] 
scala.reflect.internal.FatalError: 
    Unknown type: <notype>(NEW), <notype> [class scala.reflect.internal.Types$UniqueConstantType, class scala.reflect.internal.Types$NoType$] TypeRef? false 
    while compiling: <console> 
     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 <console> 
      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 
相關問題