列挙型と構造体【Swiftイントロダクション・第5回】

列挙型はenumを使って定義します。また、列挙型はメソッドを持つことができます。

//Int型の列挙型
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)
        }
    }
}
let ace = Rank.ace
let aceRawValue = ace.rawValue

スクリーンショット

上の例ではInt型の列挙型が宣言されています。デフォルトでは0から順番に値が割り当てられますが、明示的に値を指定することでデフォルトの挙動を変更することができます。例えば、上の例では、aceに明示的に1が与えられているので、0からではなく、1から連番で値が与えられます。値型の列挙型には整数値以外にも、浮動小数点数値(floating-point numbers)と文字列(string)を割り当てることができます。列挙型の値を取り出す場合は、rawValueプロパティーを使います。上の例では、rawValueを使ってaceの値を取り出しています。

init?(rawValue:)を使って、値から列挙型のインスタンスを作ることができます。引数に対応する値がある場合には、対応する値が、ない場合にはnilが返ってきます。

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

例えば、rawValueに12を入れてRankという列挙型のインスタンスを生成した場合、12はqueenと一致するのでswitch文のところで”queen”が返されます。そのため、threeDescriptionにはqueenが入ります。

スクリーンショット

また、3を入れてインスタンスを生成した場合には、3はcaseに対応する値がないので、デフォルトが実行され、rawValueでセットされた値が文字列としてそのままプリントされます。
スクリーンショット

列挙におけるcaseの値は、ただcaseに割り当てられている値を返すのではなく、意味のある値が入ります。もし値が不要の場合には、caseの値を記述する必要はありません。

enum Suit {
    case spades, hearts, diamonds, clubs
    func simpleDescription() -> String {
     //このselfはSuitを指している
        switch self {
        case .spades:
            return "spades"
        case .hearts:
            return "hearts"
        case .diamonds:
            return "diamonds"
        case .clubs:
            return "clubs"
        }
    }
}
//heartsの型が明示されていないのでSuitをつける
let hearts = Suit.hearts
let heartsDescription = hearts.simpleDescription()

上記の例で、heartsケースが参照される方法が2つあることに注意してください。定数のheartsに値を代入する場合は、heartsの型が明示されていないので、Suit.heartsが使われています。 switch文の中では、短縮系の.heartsが使われています。この場合は、selfがもう既にsuitを指していることが分かっているので、短縮系が使われています。このように、値の型が分かっている時には、いつでも短縮系を使うことができます。

もしケースに値を割り当てたい場合、2つの方法があります。一つ目は列挙型の宣言時に値を割り当てる方法です。しかし、この場合はケースは毎回同じ値を返します。 もう一つの方法は、列挙型のインスタンスを作る時に、それぞれのケースに関連する値を割り当てる方法です。この方法では、ケースのインスタンスごとに値を変えることができます。下の例では、サーバーに日の出と日の入りの時間をリクエストしています。サーバーは通信が成功した場合には、リクエストされた情報(下の例だと日の出・日の入り時間)を返します。失敗した場合にはエラーメッセージを返します。

enum ServerResponse {
    case result(String, String)
    case failure(String)
}

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

//resultが実行される
switch success {
case let .result(sunrise, sunset):
    print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
    print("Failure...  \(message)")
}

スクリーンショット

構造体はstructを使って定義します。構造体は関数や初期化などクラスと同じような機能を持っています。最も重要な違いの一つは、変数に入れられるとき構造体は常にコピーが渡されますが、クラスは参照が渡されるという点です。

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()

スクリーンショット