【Swift】列挙型

#列挙型
列挙型とは値型の一種で、複数の識別子（データを識別するもの）を格納する型です。
そしてこれらの識別子はケースと呼ばれ、この各ケースは排他的な関係を保っています。
そのため、複数のケースを同時に保持したりすることができません。これは、曜日で例えると火曜日であると同時に水曜日でもあることがありえない事を想像していただけるとわかりやすいと思います。

##定義方法
定義方法は下記のコードのようにenumの後に列挙型名を記述し、{}内にcaseの後にケース名を記述すれば定義完了です。

```
enum 列挙型名 {
  case ケース名1
  case ケース名2
}
```

**サンプルコード**

```
enum Weekday {
  case sunday
  case monday
  case tuesday
  case thursday
  case friday
  case saturday
}
let sunday = Weekday.sunday

print(sunday)

//実行結果
sunday
```

**イニシャライザの利用**
下記のコードのようにイニシャライザを使用し、引数に対応したケースを出力することも可能です。
このコードでは、引数に"日"を指定することでそれの英名のsundayが出力されています。

```
enum Weekday {
  case sunday
  case monday
  case tuesday
  case wednesday
  case thursday
  case friday
  case saturday

  init?(japaneseName: String) {
    switch japaneseName {
      case "日": self = .sunday
      case "月": self = .monday
      case "火": self = .tuesday
      case "水": self = .wednesday
      case "木": self = .thursday
      case "金": self = .friday
      case "土": self = .saturday
      default: return nil
    }
  }
}

let sunday =  Weekday(japaneseName: "日")

print(sunday)

//実行結果
Optional(Weekday.sunday)
```

**コンピューテッドプロパティの利用**
列挙型ではイニシャライザ以外にプロパティやメソッドなども使うことができます。
しかし一つ注意点として、ストアドプロパティは使用することができないので気をつけてください。

```
enum Weekday {
  case sunday
  case monday
  case tuesday
  case wednesday
  case thursday
  case friday
  case saturday
  
//値を保持できないコンピューテッドプロパティ
  var name: String {
//プロパティ内部でswitch文でcaseごとに返す値を分岐
    switch self {
      case .sunday:    return "日"
      case .monday:    return "月"
      case .tuesday:   return "火"
      case .wednesday: return "水"
      case .thursday:  return "木"
      case .friday:    return "金"
      case .saturday:  return "土"
    }
  }
}

let weekday = Weekday.monday
let name = weekday.name

print(name)

//実行結果
月
```

##ローバリュー
列挙隊の各ケースには対応する値を設定することができ、その値のことをローバリューと言います。
列挙隊内の全てのローバリューの型は同一に統一することができ、Int型、Double型、String型、Character型などに指定可能です。
ローバリューの定義方法は型名の後に:(コロン)とローバリュの肩を記述すればOKです。

```
enum 列挙型名 :　ローバリューの型 {
  case ケース名1 = ローバリュー1
  case ケース名2 = ローバリュー2
}
```
**Character型での定義**
下記はローバリュー#に対応したcaseを出力するコードです。

```
enum Symbol : Character {
  case sharp = "#"
  case dollar = "$"
  case percent = "%"
}

let symbol = Symbol(rawValue: "#") 

print(symbol)

//実行結果
sharp
```

**ローバリューのデフォルト値**
Int型とString型にはローバリューにデフォルト値が設定されており、Int型の場合最初のケースが0でそれ以降は最初のローバリューに1足していく形になります。
そのため下記のコードでは値が設定されているundefined以外のケースでは上から0、1、２というようにデフォルト値が設定されます。

```
enum Option : Int {
  case none
  case one
  case two
  case undefined = 999
}

Option.none.rawValue
Option.one.rawValue
Option.two.rawValue
Option.undefined.rawValue

//実行結果
0
1
2
999
```
String型に関してはcase名がそのままローバリューになります。

```
enum Direction : String {
  case north
  case east
  case south
  case west
}

Direction.north.rawValue

//実行結果
north
```

##連想値
列挙型のインスタンスはケースの情報に加えて連想値という付加情報を保持することができます。
以下のサンプルコードでは色表現方法のRGBとCMYKを例としたものです。列挙隊から連想値を取り出すためには、switch文などでバリューバインディングパターンを使用します。
このように連想値を使用すると列挙型のインスタンスごとに違う値を保持することを可能にします。

```
enum Color {
  case rgb(Float, Float, Float)
  case cmbk(Float, Float, Float)
}

let rgb = Color.rgb(0.0, 0.33 , 0.66)
let cmyk = Color.cmyk(0.0, 0.33, 0.66, 0.99)

let color = Color.rgb(0.0, 0.33, 0.66, 0.99)

switch color {
  case .rgb(let r, let g, let b):
   print("r: \(r), g: \(g), b: \(b)")
  case .cmyk(let c, let m, let y, let k):
   print("c: \(c), m: \(m), y:\(y), k: \(k)")
}

//実行結果
r:0.0, g: 0.33, b:0.66
```