クラスと構造体では、既存の演算子の独自実装を提供することができます。これは、既存の演算子のオーバーロードとして知られています。

以降の例では、構造体に対する算術加算演算子 (+) の実装方法を示しています。算術加算演算子は、2 つのターゲットに対して作用するため二項演算子で、2 つのターゲットの間に置かれるため中置 (infix) と言われます。

この例では、2 次元位置ベクトル (x, y) の構造体 Vector2D の定義に続けて、構造体 Vector2D のインスタンスを合わせて加算する関数演算子を定義しています。

struct Vector2D {
    var x = 0.0, y = 0.0
}
func + (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y + right.y)
}

演算子関数は、オーバーロードされた演算子 (+) にマッチする関数名で、グローバル関数として定義されています。算術加算演算子は二項演算子であるため、この演算子関数は Vector2D 型の入力パラメータを 2 つ取り、Vector2D 型の出力値を返しています。

この実装では、+ 演算子の左側と右側になる Vector2D インスタンスを表現するために、入力パラメータに left と right と名付けています。この関数は、2 つの Vector2D インスタンスの x プロパティおよび yプロパティを合わせて加算した合計で、x プロパティと yプロパティを初期化した新しい Vector2D インスタンスを返しています。

この関数は、構造体 Vector2D のメソッドとしてではなく、グローバルに定義されているため、既存の Vector2D インスタンス間での中置演算子として使用することができます。

let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector は Vector2D インスタンスで、値は (5.0, 5.0)

この例では、次の図のように、ベクトル (3.0, 1.0) と (2.0, 4.0) を合わせて加算し、ベクトル (5.0, 5.0) にしています。

image: vectorAddition_2x

前置演算子と後置演算子

上の例では、二項中置演算子の実装を見てきました。クラスと構造体では、標準の単項演算子の実装を提供することもできます。単項演算子は 1 つのターゲットに作用します。ターゲットの前に置く (-a のような) 場合は前置演算子で、ターゲットの後に置く (b! のような) 場合は後置演算子です。

演算子関数を宣言するには、func キーワードの前に prefix または postfix を記述して、前置単項演算子あるいは後置単項演算子を実装します。

prefix func - (vector: Vector2D) -> Vector2D {
    return Vector2D(x: -vector.x, y: -vector.y)
}

この例では、Vector2D インスタンスの単項マイナス演算子 (-a) を実装しています。単項マイナス演算子は前置演算子であるため、この関数に prefix を付ける必要があります。

単純な数値では、単項マイナス演算子は正の値を負の相当する値に変換し、逆の場合も同じようになります。Vector2D インスタンスに対する実装では、x プロパティと y プロパティの両方に対してこの演算を実行します。

let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// negative は Vector2D インスタンスで、値は (-3.0, -4.0)
let alsoPositive = -negative
// alsoPositive は Vector2D インスタンスで、値は (3.0, 4.0)

複合代入演算子

複合代入演算子は、代入 (=) と別の演算を組み合わせます。例えば、加算代入演算子 (+=) は、加算と代入を組み合わせて 1 つの演算にします。パラメータの値が演算子関数内で直接変更されるため、複合代入演算子の入力パラメータ left を inout にします。

次の例では、Vector2D インスタンスに対する加算代入演算子関数を実装しています。

func += (inout left: Vector2D, right: Vector2D) {
    left = left + right
}

加算演算子は事前に定義しているため、ここでは加算処理を再実装する必要はありません。加算代入演算子関数は、既存の加算演算子関数を活かし、left 値と right 値を加算して left の値に設定します。

var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// original の値は (4.0, 6.0)
NOTE
デフォルトの代入演算子 (=) をオーバーロードすることはできません。複合代入演算子のみオーバーロードすることができます。同様に、三項演算子 (a ? b : c) をオーバーロードすることもできません。

等価演算子

クラスと構造体は、「等しい」演算子 (==) と「等しくない」演算子 (!=) として知られる、等価演算子のデフォルト実装を受け取りません。「等しい」の意味が型の役割に依存するため、独自の型において何が「等しい」とみなせるのかを Swift が推測することはできません。

独自の型の等価性をチェックするために等価演算子を使用するには、他の中置演算子と同じように演算子の実装を提供します。

func == (left: Vector2D, right: Vector2D) -> Bool {
    return (left.x == right.x) && (left.y == right.y)
}
func != (left: Vector2D, right: Vector2D) -> Bool {
    return !(left == right)
}

この例では、2 つの Vector2D インスタンスが等価の値であるかをチェックするために、「等しい」演算子 (==) を実装しています。Vector2D のコンテキストでは、両インスタンスの x 値と y 値が同じであることを「等しい」とみなすと意味をなすため、このロジックが演算子の実装で使用されています。また、この例では「等しくない」演算子 (!=) を実装し、単に「等しい」演算子の結果の逆を返します。

2 つの Vector2D インスタンスが等価であるかをチェックするために、これらの演算子を使用することができるようになります。

let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
    print("These two vectors are equivalent.")
}
// "These two vectors are equivalent." と出力

Portions of this page are translations based on work created and shared by Apple and used according to terms described in the Creative Commons Attribution 4.0 International License.