&+
)など、デフォルトでオーバーフローする Swift の第 2 の算術演算子を使用します。これらのオーバーフロー演算子は全て、アンパサンド(&
)で始まります。~
)は、数値の全てのビットを反転します。UInt8
整数は 8bit のデータ長を持ち、 0
から 255
の範囲で任意の値を格納できます。この例では、初めの 4bit に 0 を、続く後ろの 4bit に 1 を設定されている 2 進数の値 00001111
で UInt8
整数を初期化しています。これは、10 進数の 15
に相当します。invertedBits
の作成にビット論理否定演算子が使われています。ビットの桁数は変わらず initialBits
と同じですが、全てのビットは反転されています。0
が 1
に、1
が 0
になった invertedBits
の値は 11110000
です。これは符号なし 10 進数の 240
に相当します。&
)は、2 つの数値のビットを合成します。両方の入力数値のビットが 1
の場合にのみ、ビットが 1
になり、新しい数値を返します:firstSixBits
と lastSixBits
の値は両方とも、4 つの中間ビットに 1
が設定されています。ビット論理積演算子はそれらを組み合わせて、符号なし 10 進数の 60
に相当する数値 00111100
を作成します。|
)は、2 つのビット値を比較します。入力されたビット値において、いずれかのビットが 1
と等しい場合、そのビットを 1
とする新しいビット値を返します:someBits
と moreBits
は、異なるビットに 1
が設定されています。ビット論理和演算子はそれらを組み合わせて、符号なし 10 進数の 254
に相当するビット値 11111110
を作成します。^
)は、2 つのビット値を比較します。入力されたビット値において、いずれもビットが異なる場合は 1
、等しい場合は 0
が設定されたビット値を新たに返します:firstBits
と otherBits
のビットは、一方が持たない 1
が互いに設定されています。ビット排他的論理和演算子は、これらに 1
が設定された新しいビット値を出力します。firstBits
および otherBits
が持つ他のビットはすべて一致しているので、それらは 0
が設定されます。<<
)およびビット右シフト演算子(>>
)は、下記で定義されている規則に従って、数値内の全てのビットを特定の桁数だけ左または右に移動します。0
が挿入されます11111111 << 1
(11111111
を 1 桁左にずらしたもの)と 11111111 >> 1
(11111111
を右に 1 桁ずらしたもの)の結果を示しています。青色の数字はシフトされ、灰色の数字は破棄され、オレンジ色の空きには 0 が挿入されます。UInt32
の定数 pink
を使用しています。CSS カラー値 #CC6699
は、Swift の 16 進数で 0xCC6699
になります。そしてこの色は、ビット論理積演算子(&
)とビット右シフト演算子(>>
)によって、それぞれ赤(CC
)、緑(66
)、および青(99
)の値へ分解されます。0xCC6699
と 0xFF0000
のビット論理積演算によって得られます。0xFF0000
の 0 は 0xCC6699
の 2 番目と 3 番目のバイトを効果的に「隠蔽」し、その結果として 6699
に構わず 0xCC0000
が残ります。>> 16
)。16 進数は各ペアで 8 ビットを使用するため、右に 16 桁移動することで 0xCC0000
が 0x0000CC
に変換されます。これは 0xCC
と等しく、10 進数の 204
に相当します。0xCC6699
と 0x00FF00
のビット論理積演算から出力値 0x006600
を得られます。そしてこの出力値が右に 8 桁シフトされ、10 進数の 102
に相当する 0x66
が得られます。0xCC6699
と 0x0000FF
のビット論理積演算から出力値 0x000099
を得られます。すでに 0x000099
は 10 進数 153
に相当する 0x99
と等しいため、この値はシフトせずに使用されます。0
は正を意味し、符号ビット 1
は負を意味します。0
から数えて格納されます。Int8
で整数 4
を表すビットは次のとおりです:0
(「正」を意味します)で、7 つの値ビットは 2 進数表記で書かれた数字の 4
です。2
の n
乗から絶対値を引くことによって格納されます。ここで言う n
は値ビットの数です。8 ビットの数値には 7 つの値ビットがあるため、これは 2
の 7
乗、つまり 128
です。Int8
で整数 -4
を表す方法は次のとおりです:1
(「負」を意味する)で、7 つの値ビットは 124
の 2 進数値(128 - 4
)です:-1
を -4
に加算できます:0
に近づきます。この符号ビットを保ったまま行われるシフトは、値が 0
に近づいても負数が負の値のままになることを意味します。Int16
整数型は、-32768
から 32767
までの任意の符号付き整数を保持できます。Int16
の定数または変数に範囲外の数値を設定しようとすると、エラーが発生します。&
)で始まります。&+
)&-
)&*
)&+
)を使用して、符号なし整数を正の方向にオーバーフローさせた場合の例を次に示します:unsignedOverflow
は、UInt8
が保持できる最大値(255
、または 2 進数で 11111111
)で初期化されます。次に、オーバーフロー加算演算子(&+
)を使用して 1 ずつインクリメントします。これにより、UInt8
が保持できるサイズを超えてその 2 進数表現がプッシュされ、下の図に示すように、境界を超えてオーバーフローします。オーバーフロー加算後に UInt8
の境界内に残っている値は 00000000
、つまり 0
です:&-
)を使用した例を次に示します:UInt8
が保持できる最小値は 0
、つまり 2 進数で 00000000
です。オーバーフロー減算演算子(&-
)を使用して 00000000
から 1
を減算すると、数値はオーバーフローして 11111111
、つまり 10 進数で 255
に巻き戻ります。Int8
が保持できる最小値は -128
、つまり 2 進数で 10000000
です。オーバーフロー演算子を使用してこの 2 進数から 1
を減算すると、01111111
の 2 進数値が得られます。これは、符号ビットを切り替えて、Int8
が保持できる正の最大値 127
を返します。17
に等しい理由を説明しています。2
足す 3
は 5
に等しい5
割る 4
の余りは 1
に等しい1
かける 5
は 5
に等しい5
ではなく 17
です。優先順位の高い演算子は、優先順位の低い演算子の前に評価されます。Swift では、C 言語と同様に、剰余演算子(%
)と乗算演算子(*
)が加算演算子(+
)よりも優先されます。その結果、加算される前に両方が評価されます。()
)を追加するものだと考えてください。(3 % 4)
は 3
なので、これは次と等価です。(3 * 5)
は 15
なので、これは次と等価です。17
になります。NOTE Swift の演算子の優先順位と結合規則は、C 言語や Objective-C のものよりもシンプルで結果が予測しやすくなっています。ただし、これは、C 言語ベースの言語とまったく同じではないことを意味します。既存のコードを Swift に移植するときは、演算子の作用が意図したとおりに動作するかを確認してください。
+
)を実装する方法を示しています。算術加算演算子は、2 つのターゲットで動作するため二項演算子で、これら 2 つのターゲットの間に現れるため、_中置_と呼ばれます。(x, y)
の Vector2D
構造体を定義し、その後に Vector2D
構造体のインスタンスを加算する演算子メソッドの定義が続きます。Vector2D
の型メソッドとして定義され、オーバーロードされる演算子(+
)に一致するメソッド名を使用します。加算はベクトルの本質的な動作の一部ではないため、型メソッドは、Vector2D
のメインの宣言ではなく、extension で定義されています。算術加算演算子は二項演算子のため、この演算子メソッドは Vector2D
型の 2 つの入力パラメータを受け取り、同じく Vector2D
型の 1 つの出力値を返します。+
演算子の左側と右側にある Vector2D
インスタンスを表すために、入力パラメータに left
および right
という名前が付けられています。このメソッドは、新しい Vector2D
インスタンスを返します。このインスタンスの x
および y
プロパティは、2 つの Vector2D
インスタンスの x
プロパティと y
プロパティの合計で初期化されています。Vector2D
インスタンス間の中置演算子として使用できます。(3.0, 1.0)
と (2.0, 4.0)
を加算してベクトル (5.0, 5.0)
を作成します:-a
など)で、ターゲットの後にある場合は後置演算子(b!
など)です。func
キーワードの前に prefix
または postfix
修飾子を記述して、_前置_または_後置_単項演算子を実装します。Vector2D
インスタンスに単項減算演算子(-a
)を実装しています。単項減算演算子は前置演算子のため、このメソッドは prefix
修飾子で修飾する必要があります。Vector2D
インスタンスの対応する実装は、x
プロパティと y
プロパティの両方でこの操作を実行します:=
)と別の演算子を組み合わせます。例えば、加算代入演算子(+=
)は、加算と代入を 1 つの演算に結合します。パラメータの値は演算子メソッド内から直接変更されるため、複合代入演算子の左側の入力パラメータ型を inout
としてマークします。NOTE デフォルトの代入演算子(=
)をオーバーロードすることはできません。複合代入演算子のみをオーバーロードできます。同様に、三項条件演算子(a ? b : c
)はオーバーロードできません。
==
)および不等価演算子(!=
)として知られる等価演算子の実装がありません。通常は ==
演算子を実装し、標準ライブラリの ==
演算子の結果を否定する !=
演算子のデフォルト実装を使用します。==
演算子を実装するには 2 つの方法があります。自分で実装するか、多くの型の場合、Swift に実装を合成するよう依頼することができます。どちらの場合も、標準ライブラリの Equatable
プロトコルに準拠を追加します。==
演算子の実装は、他の中置演算子を実装するのと同じ方法で提供します:==
演算子を実装して、2 つの Vector2D
インスタンスが同等の値を持つかどうかを確認しています。Vector2D
では、「等しい」を「両方のインスタンスが同じ x
値と y
値を持つ」ことを意味すると考えるのが理にかなっているおり、==
演算子の実装で使用されているロジックです。Vector2D
インスタンスが同等かどうかを確認できるようになりました:operator
キーワードを使用してグローバルレベルで宣言され、prefix
、infix
または postfix
修飾子でマークされます。+++
という新しい前置演算子を定義しています。この演算子は Swift では既存の意味を持たないため、Vector2D
インスタンスを操作する特定のコンテキストで、独自のカスタムの意味が与えられます。この例では、+++
は新しい「前置ダブリング」演算子として扱われます。前に定義した加算代入演算子を使用してベクトルにそれ自体を追加することにより、Vector2D
インスタンスの x
値と y
値を 2 倍にします。+++
演算子を実装するには、次のように +++
という型メソッドを Vector2D
に追加します。AdditionPrecedence
に属する +-
という新しいカスタム中置演算子を定義しています:x
値を加算し、最初のベクトルから 2 番目のベクトルの y
値を減算します。これは本質的に「加算」演算子のため、+
や -
などの加算中置演算子と同じ優先順位グループが与えられています。演算子の優先順位グループと結合規則設定の完全なリストを含む、Swift 標準ライブラリによって提供される演算子については、Operator Declarations(演算子宣言)を参照ください。優先順位グループの詳細と、独自の演算子と優先順位グループを定義するための構文については、Operator Declarations(演算子の宣言)を参照ください。NOTE 前置または後置演算子を定義するときは、優先順位を指定しません。ただし、前置と後置演算子の両方を同じオペランドに適用すると、後置演算子が最初に適用されます。
if
や for
などの通常の Swift 構文を含めることができます。Drawable
プロトコルは、線や形状などの描画可能なものの要件を定義します: 型は draw()
メソッドを実装する必要があります。 Line
構造体は 1 行の描画を表し、ほとんどの描画のトップレベルのコンテナとして機能します。Line
を描画するために、構造体は各コンポーネントの draw()
を呼び出し、結果の文字列を単一の文字列に連結します。Text
構造体は、文字列をラップして描画の一部にします。AllCaps
構造体は、別の描画をラップしてテキストを大文字に変換します。AllCaps
の後の深くネストされた括弧は読みにくく、name
が nil
の場合に「World」を使用するフォールバックロジックは、??
を使用してインラインで実行する必要があります。これは、より複雑なものに対しては困難です。描画の一部を構成するために switch
または for
ループを含める必要があっても、方法はありません。リザルトビルダを使用すると、このようなコードを書き換えて、通常の Swift のコードのように見せることができます。@resultBuilder
属性を記述します。例えば、次のコードは DrawingBuilder
というリザルトビルダを定義します。これにより、宣言的な構文を使用して描画できます:DrawingBuilder
構造体は、リザルトビルダ構文の一部を実装する 3 つのメソッドを定義します。buildBlock(_:)
メソッドは、コードのブロックに一連の行を書き込むためのサポートを追加します。そのブロック内のコンポーネントを Line
に結合します。 buildEither(first:)
および buildEither(second:)
メソッドは、if-else
のサポートを追加します。@DrawingBuilding
を関数のパラメータに適用すると、関数に渡されたクロージャを、リザルトビルダがそのクロージャから作成する値に変換します。例えば:makeGreeting(for:)
関数は name
パラメータを受け取り、それを使用してパーソナライズされた挨拶を描画します。draw(_:)
関数と caps(_:)
関数はどちらも、@DrawingBuilder
属性でマークされた単一のクロージャを引数として受け取ります。これらの関数を呼び出すときは、DrawingBuilder
が定義する特別な構文を使用します。Swift は、描画の宣言的な記述を DrawingBuilder
のメソッドへの一連の呼び出しに変換し、関数の引数として渡される値を構築します。例えば、Swift は caps(_:)
の呼び出しを次のようなコードに変換します:if-else
ブロックを buildEither(first:)
および buildEither(second:)
メソッドの呼び出しに変換します。これらのメソッドを自身で呼び出すことはありませんが、DrawingBuilder
構文を使用すると、変換の結果を表示して、 Swift がコードをどのように変換するかを簡単に確認できます。for
ループをサポートするには、buildArray(_:)
メソッドを追加します。for
ループが描画の配列を作成し、buildArray(_:)
メソッドがその配列を Line
に変換します。