如何在scala中创建具有额外字段的枚举

时间:2011-06-24 20:30:45

标签: scala enums

在Java中我有类似的东西

public enum FlatFileHeaderMapping {

   HEADER_EL(1),
   HEADER_RESERVED1(5),
   HEADER_RESERVED2(2),
   HEADER_MESSAGE_TYPE(4)

   public final int fieldSize;

    private FlatFileHeaderMapping(int fieldSize) {
        this.fieldSize = fieldSize;
   }

}

然后我可以使用它将每一行放入地图中,然后通过此枚举(如符号)访问地图中的键

就我所见,枚举没有这种质量,并且case类没有像枚举声明那样排序 - 因此不能用于匹配记录布局,如上所示。至少没有有序集合的支持。

我可能会遗漏一些明显的东西,因此问题就在这里!

由于

6 个答案:

答案 0 :(得分:13)

过度思考是正确的,但是有一种不那么冗长的方式来声明案例对象:

sealed abstract class FlatFileHeaderMapping(val fieldSize: Int)
case object HEADER_EL extends FlatFileHeaderMapping(1)
case object HEADER_RESERVED1 extends FlatFileHeaderMapping(5)
case object HEADER_RESERVED2 extends FlatFileHeaderMapping(2)
case object HEADER_MESSAGE_TYPE extends FlatFileHeaderMapping(4)

答案 1 :(得分:4)

您可以尝试使用case object s:

sealed trait FlatFileHeaderMapping { val fieldSize: Int }                                                                                                                                                                          
case object HEADER_EL extends FlatFileHeaderMapping { val fieldSize = 1 }                                                                                                  
case object HEADER_RESERVED1 extends FlatFileHeaderMapping { val fieldSize = 5 }                                                                                           
case object HEADER_RESERVED2 extends FlatFileHeaderMapping { val fieldSize = 2 }                                                                                           
case object HEADER_MESSAGE_TYPE extends FlatFileHeaderMapping { val fieldSize = 4 } 

然后您可以像这样使用枚举:

object Test {                                                                                                                                                              
  def foo(x: FlatFileHeaderMapping) {                                                                                                                                      
    val result =                                                                                                                                                           
      x match {
        case HEADER_EL => "it's a HEADER_EL!"                                                                                                                              
        case other => "its field size is: " + other.fieldSize                                                                                                             
      }                                                                                                                                                                    
    println(result)                                                                                                                                                        
  }                                                                                                                                                                        

  def main(args: Array[String]) {                                                                                                                                          
    foo(HEADER_EL)                                                                                                                                                         
    foo(HEADER_MESSAGE_TYPE)                                                                                                                                               
  }                                                                                                                                                                        
}

您在这里获得的主要精力是编译时检查是否处理了所有枚举值。即在上面的x match { ... }代码中,如果您没有'case other =>,则会出现编译错误。 ......那里的条款。

我几乎只是重述this answer,其中列出了这种方法的优点和缺点。

答案 2 :(得分:2)

答案 3 :(得分:1)

object Direction extends Enumeration {
  val North = Value("North")
  val East = Value("East")
  val South = Value("South")
  val West = Value("West")
}

scala> import Direction._
scala> values foreach println
scala> val map = HashMap(North -> 1, South -> 2)

答案 4 :(得分:0)

这在Enumeration with constructor and lookup table

中得到了解答

整数值存在一个更简单的解决方案:

object FlatFileHeaderMapping extends Enumeration  {
   type FlatFileHeaderMapping = Value 
   val HEADER_EL = Value(1, "HEADER_EL")
   val HEADER_RESERVED1 = Value(5, "HEADER_RESERVED1")
   val HEADER_RESERVED2 = Value(2, "HEADER_RESERVED2")
   val HEADER_MESSAGE_TYPE = Value(4, "HEADER_MESSAGE_TYPE")
}

答案 5 :(得分:0)

再现已接受答案的内容,因为它隐藏在损坏的Tumblr链接(我通过Archive.org访问)后面,该链接又指向this page

trait Enum { //DIY enum type
  import java.util.concurrent.atomic.AtomicReference //Concurrency paranoia

  type EnumVal <: Value //This is a type that needs to be found in the implementing class

  private val _values = new AtomicReference(Vector[EnumVal]()) //Stores our enum values

  //Adds an EnumVal to our storage, uses CCAS to make sure it's thread safe, returns the ordinal
  private final def addEnumVal(newVal: EnumVal): Int = { import _values.{get, compareAndSet => CAS}
    val oldVec = get
    val newVec = oldVec :+ newVal
    if((get eq oldVec) && CAS(oldVec, newVec)) newVec.indexWhere(_ eq newVal) else addEnumVal(newVal)
  }

  def values: Vector[EnumVal] = _values.get //Here you can get all the enums that exist for this type

  //This is the trait that we need to extend our EnumVal type with, it does the book-keeping for us
  protected trait Value { self: EnumVal => //Enforce that no one mixes in Value in a non-EnumVal type
    final val ordinal = addEnumVal(this) //Adds the EnumVal and returns the ordinal

    def name: String //All enum values should have a name

    override def toString = name //And that name is used for the toString operation
    override def equals(other: Any) = this eq other.asInstanceOf[AnyRef]
    override def hashCode = 31 * (this.getClass.## + name.## + ordinal)
  }
}

//And here's how to use it, if you want compiler exhaustiveness checking
object Foos extends Enum {
  sealed trait EnumVal extends Value /*{ you can define your own methods etc here }*/

  val F = new EnumVal { val name = "F" }
  val X = new EnumVal { val name = "X" }
}

/**
scala> Foos.values.find(_.name == "F")
res3: Option[Foos.EnumVal] = Some(F)

scala> Foos.X.ordinal
res4: Int = 1

scala> def doSmth(foo: Foos.EnumVal) = foo match {
  case Foos.X => println("pigdog")
}

<console>:10: warning: match is not exhaustive!
missing combination        $anon$1
missing combination        $anon$2

scala> def doSmth(foo: Foos.EnumVal) = foo match {
         case Foos.X => println("pigdog")
         case Foos.F => println("dogpig")
       }
doSmth: (foo: Foos.EnumVal)Unit
**/

//But if you don't care about getting exhaustiveness warnings, you can do:

object Foos extends Enum {
  case class EnumVal private[Foos](name: String) extends Value /* { you can define your own methods and stuff here } */

  val F = EnumVal("F")
  val X = EnumVal("X")
}

/**
Which is a bit less boilerplatey.


Cheers,
√
**/