2014-08-29 2 views
5

나는 an answer on SO where someone said that scala enumerations are useless을 읽었으며 실제로 필요한 경우 자바 열거 형을 대신 사용해야합니다.스칼라와 자바 열거 형의 차이점

전에 자바 열거 형을 사용했지만 자바 스크립트를 사용하지 않는 동안 완전히 이해한다고 말할 수는 없습니다.

누군가가 스칼라와 자바 열거의 차이점을 설명 할 수 있습니까? 스칼라 열거 형의 단점은 어디에 있습니까?

+0

스칼라의 열거 그 뒤에 없습니다. http://stackoverflow.com/questions/21537148/scala-java-enumerations 스칼라의 케이스 클래스/객체만큼 편리하지는 않습니다. – Naetmul

답변

8

스칼라 열거 형의 주된 단점은 메서드와 필드를 추가하는 것이 어렵다는 점입니다. Java에서는 고정 된 수의 인스턴스 (예 : 싱글 톤을 구현하는 데 적합한 이유)와 함께 클래스로 열거 형을 사용하는 것이 간단합니다.

그러나 스칼라에서 열거 형은 가능한 값 집합입니다. 메소드와 필드를 추가하는 것은 훨씬 더 해커 프로세스입니다. 열거 형에서 벗어난 사소한 동작을 원한다면 Java enum이 훨씬 더 편리한 도구입니다.

예를 들어 자바 열거는 다음과 같습니다

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

이 사소한에 나쁜 보이지 않습니다

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

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

그러나, 스칼라, 당신이해야 할 것 이런 식으로 예제를 만들지 만 혼란스러운 구문을 추가하고 열거 형의 대부분의 용도로 암시 적으로 변환해야하는 다른 클래스의 오버 헤드를 추가합니다.

Java enum에서 볼 수있는 가장 큰 장점은 당신이 의미하는 바를 정확하게 쓰는 것입니다. 일부 메소드와 필드가있는 enum입니다. 스칼라에서는, 여러분이 의미하는 것 이외의 것을 쓰고 있습니다. 원하는 메소드와 필드가있는 클래스를 포함하는 열거 형을 작성해야하며 해당 클래스에서 열거 형으로의 변환도 정의해야합니다. 똑같은 생각을 표현하기는 덜 관용적입니다.

스칼라는 in the comments으로 지적했듯이 대부분의 경우 enum의 대안으로 사용할 수있는 더 깨끗한 구문을 가지고 있습니다. Case Classes을 제공합니다. 그러나 Case 클래스가 충분하지 않은 상황 (예 : 모든 값을 반복 할 때)과 같은 경우도 있으므로 일반 열거 형이 여전히 자리를 차지합니다. 수정 : 매크로를 사용하면 사례 클래스를 반복 할 수 있지만 그렇게하면 복잡성이 추가되는 반면 스칼라 및 Java의 경우 enum은 훨씬 반복적으로 반복됩니다.

+1

세 번째 해결책은 [여기에 설명 된] 케이스 객체를 사용하는 것입니다 (http://stackoverflow.com/questions/1898932/case-classes-vs-enumerations-in-scala). –

+0

매크로를 사용하여 봉인 된 특성을 통한 반복이 가능합니다. - http://stackoverflow.com/questions/13671734/iteration-over-a-sealed-trait-in-scala – Gavin

3

스칼라의 열거의 주요 이점은 구문의 규칙 성입니다.

enum의 요소에 비헤이비어를 추가하려면 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> 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이 비트 세트 인 오늘의 스칼라에서 작동하는 것 같다 17,451,515,

다른 물건 :

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