2014-08-29 26 views
5

an answer on SO where someone said that scala enumerations are useless okudum ve gerçekten ihtiyacınız varsa java numaralarını kullanmalısınız.Scala ve java numaralandırmaları arasındaki farklar

Daha önce java numaralandırma kullanmış olsam da, günüm işimde java kodlamadığım için onları tam olarak anladığımı söyleyemem.

Birisi, scala ve java numaralandırmaları arasındaki farkları açıklayabilir ve scala enumlarındaki eksikliklerin tam olarak nerede olduğu açıklanabilir mi?

+0

Scala'nın Sayım arkasında değil. http://stackoverflow.com/questions/21537148/scala-java-enumerations Sadece Scala'nın vaka sınıfları/nesneleri kadar uygun değil. – Naetmul

cevap

8

Scala enumlarının ana zayıflığı, onlara yöntem ve alanlar eklemenin zorluğudur. Java'da, bir numarayı sabit sayıda örnek içeren bir Sınıf olarak kullanmak çok önemlidir (örneğin, tekillerin uygulanması için neden iyi bir seçenek olduğu gibi).

Scala'da, Enumlar bir dizi olası değerdir; Onlara metot ve alanların eklenmesi çok daha zor bir süreçtir. Bu nedenle, enumdan önemsiz davranışların ötesinde bir şey istiyorsanız, Java enumları çok daha kullanışlı bir araçtır.

Örneğin bir Java enum şöyle olabilir:

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) 
    .... 
} 

Bu önemsiz bir o kötü görünmüyor:

public enum Month{ 
    january(31), 
    february(28), 
    ... 
    december(31); 

    public final int daysInMonth; 
    Month(int daysInMonth){ 
     this.daysInMonth = daysInMonth; 
    } 
} 

Ancak Scala, bunu yapmak zorunda kalacak Bunun gibi bir örnek, ancak bazı kafa karıştırıcı sözdizimi ekler ve enum'un çoğu kullanımı için örtülü olarak dönüştürülmesi gereken başka bir sınıfın ek yükünü ekler.

Java enum'u gördüğüm en büyük avantaj, tam olarak ne demek istediğinizi yazmanızdır; Bazı yöntemleri ve alanları ile bir enum. Scala'da, ne demek istediğinden başka bir şey yazıyorsun; İstediğiniz yöntemlere ve alanlara sahip bir sınıf içeren bir enum oluşturmanız ve aynı zamanda bu sınıftan enum'a bir dönüşüm tanımlamanız gerekir. Aynı fikri ifade etmek için daha az deyimsel bir yol.

in the comments belirtildiği gibi, Scala birçok durumda enums alternatif olarak kullanılabilir ve çok daha temiz bir sözdizimi olan Case Classes teklif eder. Fakat yine de Case Classes'in yeterli olmadığı bazı durumlar vardır (örneğin, tüm değerler üzerinde yinelemek istediğinizde), böylece sıradan enumlar hala yerlerini alır. Düzeltme: Makroları kullanmak, Case Classes üzerinde yineleme yapmayı mümkün kılar, ancak bunu yapmak kendi ek karmaşıklığına sahiptir, enumlar (hem Scala'da hem de Java'da) yineleme yapmak için çok daha basittir.

+1

Üçüncü bir çözümün, burada tartışıldığı gibi, vaka nesneleri kullanması gerektiğine dikkat etmek gerekir (http://stackoverflow.com/questions/1898932/case-classes-vs-enumerations-in-scala). –

+0

Makrolar ile sızdırmazlık özelliği yinelenebilir - http://stackoverflow.com/questions/13671734/iteration-over-a-sealed-trait-in-scala – Gavin

3

Scala Numaralandırmanın ana avantajı, sözdiziminin düzenidir.

Enum öğelerinize davranış eklemek istiyorsanız, yalnızca Val sınıfını genişletin.

Odersky, adlandırılmış çok değerli sabitler olarak en basit kullanım durumlarından dolayı onları beğenir. Ve sadece e-posta listesine söz verdi, ilk kez, geliştirilmiş desteğin ufukta olduğu. recentlyused Ben bunları bir dizi dizesiyle değiştirdiğim için, değer kümesi bir bit dizisi olduğundan, bir dizi dizeden daha güzel görünüyor.

yerine

val stuff = List("foo", "bar", "baz") 

object stuff extends Enumeration { val foo, bar, baz = Value } 

veya

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 
             ^

Davranış:

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> 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 biraz kümesidir Bugünün Scala çalışmak gibi görünüyor

Diğer öğeler:

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 

O Scala benziyor not entirely friendly to Java enums geçerli:

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 
İlgili konular