2014-12-31 3 views
0

Я изучаю Scala, исходящую из фона Java, и первое, что я нашел, которое работает значительно по-другому, чем Java, это Enums. Мне удалось выполнить все, что я хотел, просто с помощью проб и ошибок, но я хотел бы лучше понять, что я делаю по пути.Enum.Value vs Enum # Значение

Из документации Scala, я сказал, чтобы создать перечисление путем расширения класса Enumeration, и добавить значения, приравнивая их к постоянному Value, например:

object Label extends Enumeration{ 
    val NONE = Value 
} 

Это работает примерно как и ожидалось. Моя проблема связана с использованием не только перечислений, но и расширений пользовательских расширений enum. Я написал фрагмент кода как часть класса машинного обучения (теперь) для разделения данных по их меткам (например, для использования в TDIDT). Внизу это маленький кусочек, чтобы попасть туда, где я смущен. Объект Data работает, просто чтобы попробовать.

Во-первых, заявление для печати, я думал, что это было бы верно, но это не

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

Почему это так? Разве что хотя NONE, что MessageLabel унаследовал, непосредственно из Label, система типов настаивает на том, что они являются разными значениями перечисления?


Во-вторых, и что более важно, я шел туда и обратно между Label.Value и Label#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 <: 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 вы не можете расширять перечисления в этом смысле. Для «расширения» следует добавить членов или увеличить расширение, но подклассы означают подмножество или ограниченный домен.

Это случай, когда предпочтение отдается композиции над наследованием. Учитывая набор будних дней и выходных дней, я получаю alldays, добавляя их, а не продлевая будние дни с выходными.

Here - пример использования перечисления в зависимости от пути.

Еще одна проблема с кодом, как он стоит:

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

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

2

Label#Value тип Value в типе Label. Label.Value - это тип Value в значении Label. (Это немного запутанно, потому что у вас есть как class Label, так и object Label (т. Е. Значение)). Таким образом, MessageLabel.Value является Label#Value, поскольку MessageLabel является экземпляром такого типа (class) Label. Но это не Label.Value, потому что MessageLabel не является значением (object) Label. И нет MessageLabel#Value, потому что нет class MessageLabel (или черта).

(FWIW Я нахожу scala Enumeration очень запутанным и предпочитаю использовать перечисления Java в моем коде Scala)

Смежные вопросы