列舉(Enumeration)


接續 路徑相依型態(Path-dependent type) 的說明。對於路徑相依型態,不同的路徑代表不同的型態,所以你可以將之作為快速建立特定類型的一種方式,只要指定不同的路徑,就可以馬上產生不同的型態。一個應用的實際例子是在製作列舉型態(Enumation type),例如:
class Enum {
class Value
}

object Action extends Enum {
val Up = new Value
val Down = new Value
val Left = new Value
val Right = new Value
}

object Operation extends Enum {
val Up = new Value
val Down = new Value
val Left = new Value
val Right = new Value
}

val action1: Action.Value = Action.Up
val action2: Action.Value = Operation.Up // 編譯錯誤,type mismatch

在上例中,Value為Enum的內部類別,由於路徑相依的關係,Action的Up、Down、Left、Right成員,其型態為Action.Value(別忘了,Action實際上是個參考名稱,請參考 單 例物件),而Operation的Up、Down、Left、Right成員,其型態為Operation.Value(Action.Value與Operation.Value都是一種Enum#Value),利用這種方式,可讓建立出來的列舉成員因路徑而有不同的型態。

所以,在以下的例子中,doAction()可以傳入Action.Value的列舉物件,但無法傳入Operation.Value的列舉物件:
def doAction(action: Action.Value) = action match {
case Action.Up => "上"
case Action.Down => "下"
case Action.Left => "左"
case Action.Right => "右"
}

println(doAction(Action.Down))
println(doAction(Operation.Down)) // 編譯錯誤,type mismatch

事實上,Scala本身就提供了 scala.Enumeration 類別用以建立列舉型態:
object Action extends Enumeration {
val Up = Value
val Down = Value
val Left = Value
val Right = Value
}

scala.Emuneration中有個內部抽象類別Value,以及一個無參數方法Value,無參數方法Value會傳回內部抽象類別Value的實作物件(內部Val類別實作了內部抽象類別Value)。上例也可以寫成:
object Action extends Enumeration {
val Up, Down, Left, Right = Value
}

scala.Emuneration中的Value方法還有幾個版本,像是接受String的版本可以讓你指定列舉物件的toString結果:
object Action extends Enumeration {
val Up = Value("上")
val Down = Value("下")
val Left = Value("左")
val Right = Value("右")
}

for(value <- Action) {
println(value.id + ": " + value)
}

在上例中也示範了,你可以使用foreach語法取得Action中的列舉物件,如果沒有指定列舉常數值,則預設從0開始,這可以從id屬性取得,上例會顯示:
0: 上
1: 下
2: 左
3: 右


scala.Emuneration中接受整數的Value方法,則可以讓你指定列舉常數值,而另一個同時接受整數與字串的版本則可以讓你同時指定列舉常數與列舉物件的字串描述。例如:
object Action extends Enumeration {
val Up = Value(10, "上")
val Down = Value(20, "下")
val Left = Value(30, "左")
val Right = Value(40, "右")
}

for(value <- Action) {
println(value.id + ": " + value)
}

上例會顯示
10: 上
20: 下
30: 左
40: 右


scala.Emuneration也定義了apply()方法,所以你可以使用()指定列舉常數值來取得對應的列舉物件,例如:
println(Action(10))   // 上