Scala:Enumeration

Scala开篇(目录)

先开看一下如何声明一个枚举对象

object EnumTest extends Enumeration{
  type EnumTest = Value
  val One,Two,Three = Value
}

这和我们在Java中声明有很大区别,Scala的枚举值有些特殊,它的关键是内部有一个Value类,所谓的枚举值都是通过它产生的。

如果我们不做任何约定的话,枚举值默认从0开始,依次+1

下面看一下Value类是怎么工作的。

val One,Two,Three = Value

上面代码中,分别对三个枚举元素执行Value方法,它有四个重载,它们会依次调用,源代码如下

  /** 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)

当我们编写 val One = Value 时, 调用的是Value的无参接口

protected final def Value: Value = Value(nextId)

上面的无参接口继续调用下面方法,nextId初始值是 0 ,每次构造Value对象时,自动在参数 i 的基础上加1,所以也就是我们可以为每个元素指定它的值的原因,第一个元素可以是0,也可以是其它的值,第二个元素不一定就是第一个元素+1,也可以指定任意的值

protected final def Value(i: Int): Value = Value(i, nextNameOrNull)

上面代码中我们看到 nextNameOrNull ,也就是调用了下面的接口,我们是可以为元素起名字的

protected final def Value(i: Int, name: String): Value = new Val(i, name)

我们是可以在子类中直接调用上面接口,对元素命名和指定初始值的

object EnumTest extends Enumeration{
  type EnumTest = Value
  val One,Two,Three = Value
  val Four = Value(10,"four")
}

当我们为元素命名后,就可以通过名字来找到这个枚举元素了

println(EnumTest.withName("four").id)   // 输出:10

上面提到的四个方法,最终都会调动最后一个双参数的接口,来产生枚举值,这里就会提到另一个成员 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
    //这里对nextId在i的基础上递增
    nextId = i + 1
    if (nextId > topId) topId = nextId
    //如果你给的值,比最后一个元素的值都大,那最后一个值是i
    if (i < bottomId) bottomId = i
    def id = i
    /**当我们访问其中的元素时,会调用这个方法
        比如:println(EnumTest.One)
    */
    override def toString() =
        //命过名的,就取name,没有就用nameOf产生
      if (name != null) name
      else try thisenum.nameOf(i)
      catch { case _: NoSuchElementException => "<Invalid enum: no field for #" + i + ">" }

    protected def readResolve(): AnyRef = {
      val enum = thisenum.readResolve().asInstanceOf[Enumeration]
      if (enum.vmap == null) this
      else enum.vmap(i)
    }
  }

Enumeration中有一个nmap对象,它里面保存着id和name的对应关系

private val nmap: mutable.Map[Int, String] = new mutable.HashMap

如果没有为元素命名,那么将会返回这个元素的字面内容,是通过populateNameMap方法设置的

  private def populateNameMap() {
  /**反射,取出所有声明的字段*/
    val fields = getClass.getDeclaredFields
    //进行判断,名字相符并且与返回类型相符
    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].isAssignableFrom(m.getReturnType) &&
                                                   m.getDeclaringClass != classOf[Enumeration] &&
                                                   isValDef(m))
    //循环添加到nmap中
    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))
      }
    }
  }
时间: 2024-08-06 18:44:21

Scala:Enumeration的相关文章

集合输出接口-Iterator迭代输出-古老枚举输出:Enumeration

1.Iterator迭代输出(95%) Iterator是集合输出的主要接口,那么此接口定义如下: public interface Iterator<E> { public boolean hasNext() ; // 判断是否还有下一个数据 public E next() ; // 取得当前数据 } 实现代码: 1 package cn.demo; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 import j

Scala 枚举: Enumeration 概述

Spark Scala 枚举 * Java 中的那套枚举并不能直接使用到 Scala 中* Scala 中的枚举使用轻量级 Enumeration 进行实现* Scala 中的枚举其实是一个伴随对象* Scala 中的枚举没有方法重写功能* Scala 中的枚举其实都是 Enumeration.Value 这个对象 和Java和C++不同,Scala并没有枚举类型.不过,Spark标准类库提供了一个 Enumeration类型,可以用于生成枚举,定义一个枚举类的对象,并以Value方法调用枚举中

scala.的Enumeration枚举示例(转)

简介 在scala中没有枚举类型,但在标准类库中提供了Enumeration类来产出枚举.扩展Enumeration类后,调用value方法类初始化枚举中的可能值. 内部类value实际上是一个抽象类,真正创建的是val.因为实际上是Val,所以可以为Value传入id和name.如果不指定,id就是在前一个枚举值id上加一,name则是字段名. scala枚举示例 scala枚举示例 object TrafficLightColor extends Enumeration { type Tra

Scala:映射和元组

映射是键值对偶的集合.Scala有一个通用的叫法——元组:n个对象的聚集,并不一定要相同的类型. 构造映射 键A -> 值B scala> val scores = Map("wcc100"->100)//不可变映射 scores: scala.collection.immutable.Map[String,Int] = Map(wcc100 -> 100) scala> val scores1 = scala.collection.mutable.Map

Scala:HelloWorld

代码 1 object HelloWorld { 2 def main(args: Array[String]): Unit = { 3 println("Hello world") 4 } 5 } 解说 object关键字相当于static(更确切的说法是单例模式的一种语言层面的支持),def关键字定义方法,方法参数和返回值都采用后缀形式,即:“:类型”,Unit代表void,数组的表示采用Array[T],main是特殊的入口方法. 在控制台执行“scala 对象名”,传入的参数必

Scala:Next Steps in Scala

Array 1 val greetStrings = new Array[String](3) 2 greetStrings(0) = "Hello" 3 greetStrings(1) = "," 4 greetStrings(2) = "world!\n" 5 6 for(i <- 0 to 2) 7 print(greetStrings(i)) 8 9 val numNames = Array("zero", &q

Scala:条件表达式的好处

条件表达式的好处之一是:让代码更简洁,例如在一个需要根据不同条件收集不同值的场景中,多数语言提供的代码如下: 1 var tmp = 0; 2 3 if(conditinon 1) 4 { 5 tmp = xxx; 6 } 7 else if(condition 2) 8 { 9 tmp = yyy; 10 } 11 else 12 { 13 tmp = zzz; 14 } 采用 scala 这种所有都是表达式的语言来说就简单多了,代码如下: 1 var tmp = 2 if(conditino

Scala:没有continue,break怎么办?

scala自身是没有continue,break这两个语法关键词的. 但是实际上我们还是很希望有这两个语法,那么我们是否可以自己实现呢? 从官网上搜索,我们可以找到一下关于break的类相关资料: Breaks extends AnyRef A class that can be instantiated for the break control abstraction. Example usage: val mybreaks = new Breaks import mybreaks.{bre

Scala:Dynamic

Scala开篇(目录) 从Scala 2.10 开始,增加了Dynamic类型,所有直接或间接的继承自 Dynamic 的类,都可以实现. Dynamic 继承自 Any,它的源代码中什么都没有,只有一句话. trait Dynamic extends Any 按照官方的描述,Dynamic 是一个运行动态执行的 trait 标识,它没有成员,具体的实现由编译器嵌入,它可以动态的执行任意名字的方法或参数.这个怎么理解呢,我姑且认为它是动态产生方法和字段吧. 要想使用Dynamic ,需要打开编译