Scala:Enumeration
scala的枚举的声明,与Java中声明有很大区别,Scala的枚举值有些特殊,它的关键是内部有一个Value类,所谓的枚举值都是通过它产生的。
如果我们不做任何约定的话,枚举值默认从0开始,依次+1
val Red,Blue,Purple,Black = Value
分别对四个枚举元素执行Value方法,它有四个重载(详见下面的源码),它们会依次调用
可以参考:http://blog.csdn.net/bdmh/article/details/50158311
代码示例
1package org.apache.spark 2 3object ColorEnum extends Enumeration{ 4 type ColorEnum = Value 5 val Red,Blue,Purple,Black = Value 6} 7 8object SimpleDemo { 9 def main(args: Array[String]) { 10 println(ColorEnum.Red) 11 } 12} 13 14import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet } 15import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField } 16import scala.reflect.NameTransformer._ 17import scala.util.matching.Regex 18 19/** Defines a finite set of values specific to the enumeration. Typically 20 * these values enumerate all possible forms something can take and provide 21 * a lightweight alternative to case classes. 22 * 23 * Each call to a `Value` method adds a new unique value to the enumeration. 24 * To be accessible, these values are usually defined as `val` members of 25 * the evaluation. 26 * 27 * All values in an enumeration share a common, unique type defined as the 28 * `Value` type member of the enumeration (`Value` selected on the stable 29 * identifier path of the enumeration instance). 30 * 31 * @example {{{ 32 * object Main extends App { 33 * 34 * object WeekDay extends Enumeration { 35 * type WeekDay = Value 36 * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value 37 * } 38 * import WeekDay._ 39 * 40 * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun) 41 * 42 * WeekDay.values filter isWorkingDay foreach println 43 * } 44 * // output: 45 * // Mon 46 * // Tue 47 * // Wed 48 * // Thu 49 * // Fri 50 * }}} 51 * 52 * @param initial The initial value from which to count the integers that 53 * identifies values at run-time. 54 * @author Matthias Zenger 55 */ 56@SerialVersionUID(8476000850333817230L) 57abstract class Enumeration (initial: Int) extends Serializable { 58 thisenum => 59 60 def this() = this(0) 61 62 /* Note that `readResolve` cannot be private, since otherwise 63 the JVM does not invoke it when deserializing subclasses. */ 64 protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null) 65 66 /** The name of this enumeration. 67 */ 68 override def toString = 69 ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split 70 Regex.quote(NAME_JOIN_STRING)).last 71 72 /** The mapping from the integer used to identify values to the actual 73 * values. */ 74 private val vmap: mutable.Map[Int, Value] = new mutable.HashMap 75 76 /** The cache listing all values of this enumeration. */ 77 @transient private var vset: ValueSet = null 78 @transient @volatile private var vsetDefined = false 79 80 /** The mapping from the integer used to identify values to their 81 * names. */ 82 private val nmap: mutable.Map[Int, String] = new mutable.HashMap 83 84 /** The values of this enumeration as a set. 85 */ 86 def values: ValueSet = { 87 if (!vsetDefined) { 88 vset = (ValueSet.newBuilder ++= vmap.values).result() 89 vsetDefined = true 90 } 91 vset 92 } 93 94 /** The integer to use to identify the next created value. */ 95 protected var nextId: Int = initial 96 97 /** The string to use to name the next created value. */ 98 protected var nextName: Iterator[String] = _ 99 100 private def nextNameOrNull = 101 if (nextName != null && nextName.hasNext) nextName.next() else null 102 103 /** The highest integer amongst those used to identify values in this 104 * enumeration. */ 105 private var topId = initial 106 107 /** The lowest integer amongst those used to identify values in this 108 * enumeration, but no higher than 0. */ 109 private var bottomId = if(initial < 0) initial else 0 110 111 /** The one higher than the highest integer amongst those used to identify 112 * values in this enumeration. */ 113 final def maxId = topId 114 115 /** The value of this enumeration with given id `x` 116 */ 117 final def apply(x: Int): Value = vmap(x) 118 119 /** Return a `Value` from this `Enumeration` whose name matches 120 * the argument `s`. The names are determined automatically via reflection. 121 * 122 * @param s an `Enumeration` name 123 * @return the `Value` of this `Enumeration` if its name matches `s` 124 * @throws NoSuchElementException if no `Value` with a matching 125 * name is in this `Enumeration` 126 */ 127 final def withName(s: String): Value = values.find(_.toString == s).getOrElse( 128 throw new NoSuchElementException(s"No value found for '$s'")) 129 130 /** Creates a fresh value, part of this enumeration. */ 131 protected final def Value: Value = Value(nextId) 132 133 /** Creates a fresh value, part of this enumeration, identified by the 134 * integer `i`. 135 * 136 * @param i An integer that identifies this value at run-time. It must be 137 * unique amongst all values of the enumeration. 138 * @return Fresh value identified by `i`. 139 */ 140 protected final def Value(i: Int): Value = Value(i, nextNameOrNull) 141 142 /** Creates a fresh value, part of this enumeration, called `name`. 143 * 144 * @param name A human-readable name for that value. 145 * @return Fresh value called `name`. 146 */ 147 protected final def Value(name: String): Value = Value(nextId, name) 148 149 /** Creates a fresh value, part of this enumeration, called `name` 150 * and identified by the integer `i`. 151 * 152 * @param i An integer that identifies this value at run-time. It must be 153 * unique amongst all values of the enumeration. 154 * @param name A human-readable name for that value. 155 * @return Fresh value with the provided identifier `i` and name `name`. 156 */ 157 protected final def Value(i: Int, name: String): Value = new Val(i, name) 158 159 private def populateNameMap() { 160 val fields = getClass.getDeclaredFields 161 def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType) 162 163 // The list of possible Value methods: 0-args which return a conforming type 164 val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty && 165 classOf[Value].isAssignableFrom(m.getReturnType) && 166 m.getDeclaringClass != classOf[Enumeration] && 167 isValDef(m)) 168 methods foreach { m => 169 val name = m.getName 170 // invoke method to obtain actual `Value` instance 171 val value = m.invoke(this).asInstanceOf[Value] 172 // verify that outer points to the correct Enumeration: ticket #3616. 173 if (value.outerEnum eq thisenum) { 174 val id = Int.unbox(classOf[Val] getMethod "id" invoke value) 175 nmap += ((id, name)) 176 } 177 } 178 } 179 180 /* Obtains the name for the value with id `i`. If no name is cached 181 * in `nmap`, it populates `nmap` using reflection. 182 */ 183 private def nameOf(i: Int): String = synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) } 184 185 /** The type of the enumerated values. */ 186 @SerialVersionUID(7091335633555234129L) 187 abstract class Value extends Ordered[Value] with Serializable { 188 /** the id and bit location of this enumeration value */ 189 def id: Int 190 /** a marker so we can tell whose values belong to whom come reflective-naming time */ 191 private[Enumeration] val outerEnum = thisenum 192 193 override def compare(that: Value): Int = 194 if (this.id < that.id) -1 195 else if (this.id == that.id) 0 196 else 1 197 override def equals(other: Any) = other match { 198 case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id) 199 case _ => false 200 } 201 override def hashCode: Int = id.## 202 203 /** Create a ValueSet which contains this value and another one */ 204 def + (v: Value) = ValueSet(this, v) 205 } 206 207 /** A class implementing the [[scala.Enumeration.Value]] type. This class 208 * can be overridden to change the enumeration's naming and integer 209 * identification behaviour. 210 */ 211 @SerialVersionUID(0 - 3501153230598116017L) 212 protected class Val(i: Int, name: String) extends Value with Serializable { 213 def this(i: Int) = this(i, nextNameOrNull) 214 def this(name: String) = this(nextId, name) 215 def this() = this(nextId) 216 217 assert(!vmap.isDefinedAt(i), "Duplicate id: " + i) 218 vmap(i) = this 219 vsetDefined = false 220 nextId = i + 1 221 if (nextId > topId) topId = nextId 222 if (i < bottomId) bottomId = i 223 def id = i 224 override def toString() = 225 if (name != null) name 226 else try thisenum.nameOf(i) 227 catch { case _: NoSuchElementException => "<Invalid enum: no field for #" + i + ">" } 228 229 protected def readResolve(): AnyRef = { 230 val enum = thisenum.readResolve().asInstanceOf[Enumeration] 231 if (enum.vmap == null) this 232 else enum.vmap(i) 233 } 234 } 235 236 /** An ordering by id for values of this set */ 237 object ValueOrdering extends Ordering[Value] { 238 def compare(x: Value, y: Value): Int = x compare y 239 } 240 241 /** A class for sets of values. 242 * Iterating through this set will yield values in increasing order of their ids. 243 * 244 * @param nnIds The set of ids of values (adjusted so that the lowest value does 245 * not fall below zero), organized as a `BitSet`. 246 * @define Coll `collection.immutable.SortedSet` 247 */ 248 class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet) 249 extends AbstractSet[Value] 250 with immutable.SortedSet[Value] 251 with SortedSetLike[Value, ValueSet] 252 with Serializable { 253 254 implicit def ordering: Ordering[Value] = ValueOrdering 255 def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet = 256 new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId))) 257 258 override def empty = ValueSet.empty 259 def contains(v: Value) = nnIds contains (v.id - bottomId) 260 def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId)) 261 def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId)) 262 def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id)) 263 override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id)) 264 override def stringPrefix = thisenum + ".ValueSet" 265 /** Creates a bit mask for the zero-adjusted ids in this set as a 266 * new array of longs */ 267 def toBitMask: Array[Long] = nnIds.toBitMask 268 } 269 270 /** A factory object for value sets */ 271 object ValueSet { 272 import generic.CanBuildFrom 273 274 /** The empty value set */ 275 val empty = new ValueSet(immutable.BitSet.empty) 276 /** A value set consisting of given elements */ 277 def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result() 278 /** A value set containing all the values for the zero-adjusted ids 279 * corresponding to the bits in an array */ 280 def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems)) 281 /** A builder object for value sets */ 282 def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] { 283 private[this] val b = new mutable.BitSet 284 def += (x: Value) = { b += (x.id - bottomId); this } 285 def clear() = b.clear() 286 def result() = new ValueSet(b.toImmutable) 287 } 288 /** The implicit builder for value sets */ 289 implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] = 290 new CanBuildFrom[ValueSet, Value, ValueSet] { 291 def apply(from: ValueSet) = newBuilder 292 def apply() = newBuilder 293 } 294 } 295}