Enumerations and Structures

Xcode 6.0 Beta

Swift学習中。

The Swift Programming Language.epubのA Swift Tour内のEnumerations and Structuresの項を読んだ。

列挙型の定義

以下の構文で列挙型を定義する。

enum 列挙型名 : 生値の型 {
case 列挙値1 = 値,
case 列挙値2 = 値,
case 列挙値3 = 値,
// ...
}

複数の列挙をすべてcaseで区切らずに、そのままカンマで区切って、

case 列挙値1, 列挙値2, 列挙値3

のように書いてもよい。

列挙値はそれ自体が値として機能するので、生値というのは必ずしも必要ではない。生値として指定できるのは、整数、浮動小数点数、文字列である。整数を指定した場合、自動的に連番が振られるので、たとえば最初の生値に1を割り当てたとするなら、以降は省略すれば、2, 3, 4となる。

enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
    
    func simpleDescription() -> String {
        switch self {
        case .Ace:
            return "ace"
            
        case .Jack:
            return "jack"
            
        case .Queen:
            return "queen"

        case .King:
            return "king"

        default:
            return String(self.toRaw())
        }
    }
}

let ace = Rank.Ace
let aceRawValue = ace.toRaw()

列挙型と生値との相互変換

生値と列挙型との間で変換を行うには、toRaw, fromRaw メソッドを使用する。これらのメソッドは暗黙的に作成される。

if let convertedRank = Rank.fromRaw(3) {
    let threeDescription = convertedRank.simpleDescription()
}

列挙型の各メンバは実際の値であるため、生値が意味を持たないような場合には省略できる。

列挙値の参照方法

関数の引数に列挙値を指定するときや、switch文におけるcase節のように、型が判っているような場合には、Enum型を省略して「.メンバ名」として定数(列挙値)を参照することができる。型が不明の場合は、「Enum型名.メンバ名」とする。

enum Suit {
    case Spades, Hearts, Diamonds, Clubs
    
    func simpleDescription() -> String {
        switch self {
        case .Spades:
            return "spades"
            
        case .Hearts:
            return "hearts"
            
        case .Diamonds:
            return "diamonds"
            
        case .Clubs:
            return "clubs"
        }
    }
}

let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()

構造体

構造体はほとんどクラスと同じである。ただし、クラスが参照で取り回されるのに対して、構造体は常にコピーされる。(たとえば、引数や戻り値、他の構造体変数の代入時など)

struct Card {
    var rank: Rank
    var suit: Suit
    
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}

let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()

列挙型のメンバに関連した値を持たせる

列挙のインスタンスメンバには、インスタンスに関連した値(属性のようなものだが、クラスのプロパティとは少し違う)を持たせることができる。それは生値とは違う。生値は列挙型のインスタンス間で同一のものになるが、ここで言っている「関連した値」とは、列挙のインスタンスごとに異なる値を持たせることができるということである。

以下は、サーバーレスポンスとして、日の出、日の入り時刻のセット、もしくはエラーメッセージを返すときの、レスポンス値を列挙型として扱う例である。

enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
case let .Result(sunrise, sunset):
    let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
    
case let .Error(error):
    let serverResponse = "Failure...  \(error)"
}

caseへのマッチのさせ方と、ServerResponse内の値のマッチ、抽出のさせ方に注意。




Enumは想像していたよりも少し特殊だったが、なかなか便利そうではある。


今日はここまで。