The Swift Programming Language 勉強記録 - 4

Swiftべんきょうきろく、その4、です。

Enumerations and Structures

列挙型を作りたいときはenumを使う。
一番シンプルな形は以下のような感じだろうか。

enum EnumTest {
    case Zero, One, Two, Three
}
EnumTest.Zero.hashValue // 0
EnumTest.One.hashValue // 1
EnumTest.Two.hashValue // 2
EnumTest.Three.hashValue // 3

hashValueには0から順番に値が割り当てられている。
型を指定してやると値を自分で割り当てることもでき、その場合はrawValueを使用することで値が取れる。

enum EnumTest: Int {
    case One = 1, Two, Four=4, Five, Ten=10
}
// rawValueは割り当てた値
EnumTest.One.rawValue // 1
EnumTest.Two.rawValue // 2
EnumTest.Four.rawValue // 4
EnumTest.Five.rawValue // 5
EnumTest.Ten.rawValue // 10
// hashValueはデフォルトで設定された連番値
EnumTest.One.hashValue // 0
EnumTest.Two.hashValue // 1
EnumTest.Four.hashValue // 2
EnumTest.Five.hashValue // 3
EnumTest.Ten.hashValue // 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.rawValue)
        }
    }
    
    func compare(rank: Rank) -> Int {
        let sub = self.rawValue - rank.rawValue
        if (sub == 0) {
            return sub
        } else if (sub < 0) {
            return -1
        } else {
            return 1
        }
    }
}

let king = Rank.King
let kingRawValue = king.rawValue // 13
king.simpleDescription() // "king"
Rank.Jack.compare(Rank.Ace) // 1
Rank.Jack.compare(king) // -1

イニシャライザを使用して列挙型のインスタンスを作成することも可能。

// Rank.Threeを作成
if let convertedRank = Rank(rawValue: 3) {
    let threeDescription = convertedRank.simpleDescription() // "3"
    convertedRank.rawValue // 3
}
// Rankの中にrawValue=14のものはないので作成されない
if let convertedRank = Rank(rawValue: 14) {
    let threeDescription = convertedRank.simpleDescription()
    convertedRank.rawValue
} else {
    // else節が実行される
    println("Can't convert")
}

構造体の宣言はstructキーワードを用いることで行う。

struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
    func createDeck() -> [Card] {
        var deck = [Card]()
        for suit in [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs] {
            for rank in 1...13 {
                deck.append(Card(rank: Rank(rawValue: rank)!, suit: suit))
            }
        }
        return deck
    }
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
for card in threeOfSpades.createDeck() {
    println(card.simpleDescription())
}

構造体はクラスの持つ振る舞い(メソッドやイニシャライザを持つなど)のほとんどをサポートしているが、構造体は値として構造体のコピーそのものを格納する値型であるのに対し、クラスはデータへの参照を持つ参照型であるという重要な違いを持つ。

あと、列挙型にはAssociated Values(関連値)という仕組みも提供されている。

enum ServerResponse {
    // 関連値
    case Result(String, String)
    case Error(String)
}

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

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

printResponseMsg(successRes) // "Sunrise is at 6:00 am and sunset is at 8:09 pm."
printResponseMsg(errorRes) // "Failure... Out of cheese."

第4回目、いじょーです。
関連値については「こういう書き方もできるんだー」くらいで、まだ理解が浅いな。。。
使いドコロとか追々おさえていけたらと思います。