Scala: Enumeration
Scala (directory)
First, let's take a look at how to declare an enumerated object.
object EnumTest extends Enumeration{ type EnumTest = Value val One,Two,Three = Value}
This is very different from our declaration in Java. Scala's enumerated values are somewhat special. The key is that there is a Value class internally, and the so-called enumerated values are generated through it.
If we do not make any conventions, the enumerated values start from 0 by default, followed by + 1.
The following describes how the Value class works.
val One,Two,Three = Value
In the code above, the Value method is executed for the three enumeration elements, which has four overloading and will be called in sequence. The source code is as follows:
/** Creates a fresh value, part of this enumeration. */ protected final def Value: Value = Value(nextId) /** Creates a fresh value, part of this enumeration, identified by the * integer `i`. * * @param i An integer that identifies this value at run-time. It must be * unique amongst all values of the enumeration. * @return Fresh value identified by `i`. */ protected final def Value(i: Int): Value = Value(i, nextNameOrNull) /** Creates a fresh value, part of this enumeration, called `name`. * * @param name A human-readable name for that value. * @return Fresh value called `name`. */ protected final def Value(name: String): Value = Value(nextId, name) /** Creates a fresh value, part of this enumeration, called `name` * and identified by the integer `i`. * * @param i An integer that identifies this value at run-time. It must be * unique amongst all values of the enumeration. * @param name A human-readable name for that value. * @return Fresh value with the provided identifier `i` and name `name`. */ protected final def Value(i: Int, name: String): Value = new Val(i, name)
When val One = Value is compiled, the Value-free interface is called.
protected final def Value: Value = Value(nextId)
The preceding non-parameter interface continues to call the following method. The initial Value of nextId is 0. Each time a Value object is constructed, 1 is automatically added on the basis of parameter I, that is why we can specify its value for each element. The first element can be 0 or another value, the second element is not necessarily the first element + 1, but can also specify any value.
protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
In the code above, we can see nextNameOrNull, that is, the following interface is called. We can name the element.
protected final def Value(i: Int, name: String): Value = new Val(i, name)
We can directly call the above interface in the subclass to name the element and specify the initial value.
object EnumTest extends Enumeration{ type EnumTest = Value val One,Two,Three = Value val Four = Value(10,"four")}
After we name the element, we can find the enumerated element by name.
Println (EnumTest. withName ("four"). id) // output: 10
The four methods mentioned above will eventually call the last double-parameter interface to generate enumeration values. Here we will mention another member Val.
@ SerialVersionUID (0-3501153230598116017L) protected class Val (I: Int, name: String) extends Value with Serializable {def this (I: Int) = this (I, nextNameOrNull) def this (name: String) = this (nextId, name) def this () = this (nextId) assert (! Vmap. isDefinedAt (I), "Duplicate id:" + I) vmap (I) = this vsetDefined = false // here the nextId is incremented on the basis of I nextId = I + 1 if (nextId> topId) topId = nextId // if you give the value, it is larger than the value of the last element. The last value is I if (I <bottomId) bottomId = I def id = I/**. When we access the element, this method is called, for example, println (EnumTest. one) */override def toString () = // if the name is too old, the name is used. if no name is used, the if (name! = Null) name else try thisenum. nameOf (I) catch {case _: NoSuchElementException =>"
"} Protected def readResolve (): AnyRef = {val enum = thisenum. readResolve (). asInstanceOf [Enumeration] if (enum. vmap = null) this else enum. vmap (I )}}
Enumeration has an nmap object, which stores the correspondence between id and name.
private val nmap: mutable.Map[Int, String] = new mutable.HashMap
If the element is not named, the literal content of the element is returned, Which is set through the populateNameMap method.
Private def populateNameMap () {/** reflection, retrieve all declared fields */val fields = getClass. getDeclaredFields // determines whether the name matches and the returned type. def isValDef (m: JMethod) = fields exists (fd => fd. getName = m. getName & fd. getType = m. getReturnType) // The list of possible Value methods: 0-args which return a conforming type val methods = getClass. getMethods filter (m => m. getParameterTypes. isEmpty & classOf [Value]. isAssignableFr Om (m. getReturnType) & m. getDeclaringClass! = ClassOf [Enumeration] & isValDef (m) // cyclically add methods foreach {m => val name = m. getName // invoke method to obtain actual 'value' instance val Value = m. invoke (this ). asInstanceOf [Value] // verify that outer points to the correct Enumeration: ticket #3616. if (value. outerEnum eq thisenum) {val id = Int. unbox (classOf [Val] getMethod "id" invoke value) nmap + = (id, name ))}}}