[Swift5] 演算子の定義・機能追加を行う – CGSizeで四則演算を行う例

2019年4月7日(更新: 2019年4月29日)

Swift では、数値の四則演算に使用する演算子(+, -, *, /)に数値以外の演算機能を追加したり、全く新しい演算子を定義したりすることができます。

この記事では CGSize に足し算と掛け算の演算子を利用できるように機能を追加する例を通して、演算子の機能拡張及び新しい演算子の定義方法について紹介します。

CGSize同士の足し算

構造体である CGSize は、デフォルトでは演算子による計算ができません。

演算子拡張前のCGSize同士の足し算

しかし、以下のように演算子の機能を拡張することで CGSize のプロパティを直接演算させることができます。

extension CGSize {
    static func +(rect1: CGSize, rect2: CGSize) -> CGSize {
        return CGSize(width: rect1.width + rect2.width, height: rect1.height + rect2.height)
    }
}

これは、加算の演算子(+)の左右に書いた CGSize の変数を引数として受け取り、それぞれの幅と高さのプロパティを足した新しい CGSize を返すという処理を追加するコードです。これによって、実行結果は以下のようになります。

演算子のオーバーロードによるCGSizeの加算

CGSizeと数値の掛け算

同じように CGSize と数値(CGFloatなど)の計算も定義することができます。

以下は、CGSizeの幅と高さに指定した数値を乗算できるように演算子を拡張する例です。

extension CGSize {
    static func +(rect1: CGSize, rect2: CGSize) -> CGSize {
        return CGSize(width: rect1.width + rect2.width, height: rect1.height + rect2.height)
    }

    static func *(rect: CGSize, ratio: CGFloat) -> CGSize {
        return CGSize(width: rect.width * ratio, height: rect.height * ratio)
    }
}

これによって CGSize に数値を掛けて大きさを簡単に倍増させることができます。

CGSizeに数値(CGFloat)を掛けられるように演算子を拡張した例

新しい演算子を定義する

よく行う処理だけど毎回書くと煩雑になるというような計算がある場合、新しい演算子を定義することで簡潔な記述とすることができるかも知れません。

例として、幅と高さをそれぞれ二乗してから引くという演算子を定義してみましょう。

自作の演算子を定義する場合、グローバルレベルに演算子を定義する文が必要になります。

// 新しい演算子の定義
infix operator ^-

extension CGSize {
    static func ^-(rect: CGSize, rect2: CGSize) -> CGSize {
        return CGSize(width: pow(rect.width, 2) - pow(rect2.width, 2), height: pow(rect.height, 2) - pow(rect2.height, 2))
    }
}

let size1 = CGSize(width: 10, height: 20)
let size2 = CGSize(width: 5, height: 10)

print(size1 ^- size2)

実行結果は以下の通りです。

自作の演算子を利用した計算

この例では2つの数値を取る演算子を定義しましたが infix の部分を prefix や postfix に変更することで、前置や後置の演算子を定義することもできます。

演算子に使用できる文字については以下のドキュメントを御覧ください。

Lexical Structure — The Swift Programming Language (Swift 5)

演算子の優先順位を変更する

通常の四則演算において、掛け算は足し算よりも優先して計算されます。このような演算子の優先順位を設定及び変更することが可能です。

また、新しく定義した演算子を他の演算子と同時に使うには、優先順位の設定が必要となります。

以下は、足し算を掛け算と同じ優先順位(MultiplicationPrecedence)に変更し、新しく定義した演算子の優先順位を足し算と同じ(AdditionPrecedence)に設定した場合のコードです。

infix operator +: MultiplicationPrecedence
infix operator ^-: AdditionPrecedence

extension CGSize {
    static func ^-(rect: CGSize, rect2: CGSize) -> CGSize {
        return CGSize(width: pow(rect.width, 2) - pow(rect2.width, 2), height: pow(rect.height, 2) - pow(rect2.height, 2))
    }
    
    static func +(rect1: CGSize, rect2: CGSize) -> CGSize {
        return CGSize(width: rect1.width + rect2.width, height: rect1.height + rect2.height)
    }
}

let size1 = CGSize(width: 10, height: 20)
let size2 = CGSize(width: 5, height: 10)

print(size1 ^- size2 + size1)

実行結果は以下の通りです。

演算子の優先順位を変更した場合の計算結果

優先順位の詳細な指定方法は以下のドキュメントを御覧ください。

Operator Declarations | Apple Developer Documentation

以上、演算子の定義及び機能追加の方法についてでした。

参考

Advanced Operators — The Swift Programming Language (Swift 5)

CGSize – Core Graphics | Apple Developer Documentation

コメントを残す

メールアドレスが公開されることはありません。