2014-12-31 2 views
0

스칼라가 자바 배경에서 나오는 것을 배우고 있으며, Java와는 상당히 다른 방식으로 작동하는 것으로 밝혀진 첫 번째 항목은 열거 형입니다. 나는 시행 착오를 통해 내가 원하는 모든 것을 성취 할 수 있었지만 나는 그 길을 따라 무엇을하고 있는지 더 잘 이해하고 싶다. 스칼라 문서에서 Enum.Value vs Enum # 값

는, 나는, 예를 클래스 Enumeration을 확장하여 열거를 생성하고, 일정한 Value에 동일하게 설정하여 값을 추가하라고 해요 :

object Label extends Enumeration{ 
    val NONE = Value 
} 

이 예상대로에 대해 작동합니다. 내 문제는 열거 형뿐만 아니라 사용자 정의 작성된 열거 형 확장의 확장을 사용하여 온다. 필자는 Machine Learning 클래스의 일부로 코드를 작성하여 레이블별로 데이터를 분리했습니다 (예 : TDIDT에서 사용하기 위해). 아래쪽에는 내가 혼란스러워하는 곳의 작은 조각이 있습니다. Data 개체는 실행 가능하며 시도해 볼 수 있습니다.

먼저, 인쇄 문에, 나는 그것이 사실 일 것이라고 생각하지만

println(Label.NONE.equals(MessageLabel.NONE))//Thought this would be true, is false 

왜 이런 경우가 아닌가? MessageLabel이 상속 한 NONE이 Label에서 직접 가져 왔지만 형식 시스템이 다른 열거 형 값이라고 주장합니까?


두 번째로 더 중요한 기본적으로 내가 다짜고짜 Label.ValueLabel#Value 사이에 앞뒤로 가고 있었어요. 내가 함께 게시 버전 :

  • def splitByLabel[T <: Label#Value]
  • trait Labelable[T <: Label#Value]
  • abstract class Data[T <: Label#Value]
  • class Message(... val label : MessageLabel.Value)

컴파일하고 제대로 실행됩니다. 내가 .에 모든 #의 변경 때, 나는 진술 라인 splitByLabel(messages).foreach(a => println(a))에 컴파일 시간 오류 :

유추 형식 인수 [MessageLabel.Value] 방법 splitByLabel의 형식 매개 변수의 경계 [T <을 준수하지 않는 : 내가 # s의 모든 .의를 변경할 때 Label.Value]

는, 나는 진술 라인 class Message(val index : Int, val s : Map[Double, Int], override val label : MessageLabel#Value) extends Data[MessageLabel#Value](label)에 컴파일 시간 오류 :

찾을 수 없음 : 유형 MessageLabel

명확하게 두 가지의 차이점이 있으며 각각 특정 역할을 수행합니다. 다른 사람이 그 차이점을 이해하도록 도와 줄 수 있습니까? 고맙습니다!

/** Enum type all labels should extend. Guarantees access of universal NONE label */ 
class Label extends Enumeration{ 
    val NONE = Value 
} 
/** Singleton instance for accessing NONE */ 
object Label extends Label{} 

/** Companion object to all data classes. Hosts helper methods and a runnable main method */ 
object Data{ 
    /** Returns a map of lists, each list is similarly labeled data. Map is label -> list of data */ 
    def splitByLabel[T <: Label#Value](elms : List[Labelable[T]]) : Map[T, List[Labelable[T]]] = { 
    def f(acc : Map[T, List[Labelable[T]]], e : Labelable[T]) : Map[T, List[Labelable[T]]] = { 
     if(acc.contains(e.label)){ 
     val l = acc(e.label) 
     acc - e.label + ((e.label, (e :: l))) 
     } else{ 
     acc + ((e.label, List(e))) 
     } 
    } 
    elms.foldLeft(Map[T, List[Labelable[T]]]())(f) 
    } 

    def main(args : Array[String]){ 
    println(Label.NONE.equals(MessageLabel.NONE)) 

    val messages : List[Message] = (0 to 10).toList.map(a => 
     new Message(a, Map(), if(a % 3 == 0) MessageLabel.HAM else MessageLabel.SPAM)) 
    splitByLabel(messages).foreach(a => println(a)) 
    } 
} 

/** Implementing classes can be labeled */ 
trait Labelable[T <: Label#Value]{ 
    /** Returns the label of this thing */ 
    val label : T 
    /** The possible labelings for this thing */ 
    val labels : List[T] 
} 

abstract class Data[T <: Label#Value](override val label : T) extends Labelable[T]{ 
    override def toString(): String = { 
    if (label != null) 
     label.toString 
    else 
     "NO_LABEL" 
    } 
} 

object MessageLabel extends Label{ 
    val HAM, SPAM = Value 
} 

/** An instance represents a sentence. */ 
class Message(val index : Int, val s : Map[Int, Double], override val label : MessageLabel.Value) 
    extends Data[MessageLabel.Value](label){ 
    /** Returns the possible labelings for a message */ 
    override val labels = MessageLabel.values.toList 

    /** Adds index to tostring at front */ 
    override def toString() : String = { 
    index + "-" + super.toString 
    } 
} 

답변

2

이것은 열거 형에 국한되지 않습니다.

scala> class A { class B ; val None = new B } 
defined class A 

scala> class C extends A ; class D extends A 
defined class C 
defined class D 

scala> val c = new C ; val d = new D 
c: C = [email protected] 
d: D = [email protected] 

scala> c.None == d.None 
res0: Boolean = false 

누구도 이것이 사실 일 것으로 기대하지 않습니다.하나의 값은 하나의 (수퍼) 생성자에서 초기화되고 다른 하나는 다른 생성자에서 초기화됩니다.

또한 Value은 상수가 아닙니다. "다른 가치를주세요."라고 말하는 기능입니다. 따라서 각 인스턴스에 대한 값을 생성합니다.

Java에서는 이러한 의미에서 열거 형을 확장 할 수 없습니다. "확장"은 구성원을 추가하거나 확장을 늘리는 것이지만 서브 클래 싱은 하위 집합 또는 제한된 도메인을 의미합니다.

이것은 상속을 통한 구성을 선호하는 경우입니다. 평일과 주말의 세트를 감안할 때, 나는 주말을 평일 연장하지 않고 그것들을 추가하여 주를 대신합니다.

Here은 경로 종속 방식으로 열거 형을 사용하는 예입니다.

코드의 또 다른 문제는 스탠드로 :

scala> MessageLabel.NONE 
res4: MessageLabel.Value = <Invalid enum: no field for #0> 

https://issues.scala-lang.org/browse/SI-5147

2

Label#Value는 유형 Label의 유형 Value입니다. Label.Value값이LabelValue입니다. (class Labelobject Label (즉, 값)이 모두 있기 때문에 조금 혼란 스럽습니다.) 따라서 은 (class) Label의 인스턴스이므로 MessageLabel.ValueLabel#Value입니다. 그러나 MessageLabel이 (object) Label이 아니기 때문에 Label.Value이 아닙니다. class MessageLabel (또는 특성)이 없기 때문에 MessageLabel#Value이 없습니다.

(FWIW 스칼라 Enumeration은 매우 혼란스럽고 스칼라 코드에서 Java enums를 사용하는 것을 선호 함)