[iOS][Swift] switch文でも使える演算子のオーバーロード

2016.05.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

SwiftではC++であるような演算子のオーバーロードにも対応しています。
今回はそんな演算子のオーバーロードがswitch文にも適用出来るよという話です。

演算子のオーバーロードとは?

まずは演算子のオーバーロードについて簡単におさらいです。
演算子のオーバーロードは演算子について独自に拡張をすることが出来ます。
また、グローバル関数として定義する必要があります。

サンプル

例えば、独自定義した構造体 Card があるとします。
このCardはトランプカードの構造体です。

struct Card {

    enum Suit: Character {
        case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣"
    }

    enum Rank: Int {
        case Ace = 1, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King
    }

    let rank: Rank, suit: Suit
}

Card同士を+で足した場合エラーになります。(当たり前ですが。。。)
ViewController_swift
そこで、独自でCardを足すとカードの数字の合計値を返す演算子のオーバーロードを作ります。

func + (left: Card, right: Card) -> Int {
    return left.rank.rawValue + right.rank.rawValue
}

すると、以下のコードが通るようになり、Card + Card は、カードの数字を足した結果が返ってきます。

        let card1 = Card(rank: .Ace, suit: .Spades)
        let card2 = Card(rank: .Seven, suit: .Hearts)
        let addRank = card1 + card2

        print(addRank) // 8 が表示される(Int型)

switch文の演算子オーバーロード

switch文の演算子オーバーロードには、 ~= 演算子を使用します。

サンプル

上のサンプルで使ったCard構造体を再度使用します。
Cardに対して直接マーク(suit)をswitch文で書いても通常はエラーになります。 ViewController_swift 2
~= を使用し、独自でCardを比較する演算子オーバーロードを作ります。

func ~= (pattern: Character, value: Card) -> Bool {
    return pattern == value.suit.rawValue
}

pattern は caseの値に対応します。
~= のオーバーロードを作成することにより、下記のコードが通るようになります。

        let card = Card(rank: .Jack, suit: .Clubs)

        switch card {
        case "♠": break
        case "♡": break
        case "♢": break
        case "♣": break
        default:
            print("not match")
        }

また、

func ~= (pattern: Int, value: Card) -> Bool {
    return pattern == value.rank.rawValue
}

のように書くと、

        switch card {
        case 1:
            print("カードは1です")
        case 11:
            print("カードは11です")
        default:
            print("カードは1と11ではありません")
        }

のように書けます。(ヒドい感じの例ですが、、、)
また、func ~= (pattern: Character, value: Card) -> Bool {...}func ~= (pattern: Int, value: Card) -> Bool {...} は併用して使えます。
上記の例ですと、caseにCharacterを記載した場合はマークを、Intを記載した場合はカードの数字と比較します。

さいごに

内容的には小ネタレベルの話ですが、The Swift Programming Language (Swift 2.2) の Expression Patternの部分を読んでいた時に、switch文は~=で出来るのを知ったのでメモとして記事に残しておきます。