Swift Language
上級者
サーチ…
カスタム演算子
Swiftは、カスタム演算子の作成をサポートしています。新しい演算子はoperator
キーワードを使用してグローバルレベルで宣言されます。
オペレータの構造は、オペランドの配置、優先順位、および結合性の3つの部分で定義されます。
prefix
、infix
とpostfix
修飾は、カスタム演算子宣言を開始するために使用されています。prefix
とpostfix
修飾子は、演算子が動作する前の値であるか、後であるかを宣言します。このような演算子は、1つのターゲットに対してのみ動作できるため、8
および3++
**のようなurnaryです。infix
、バイナリ演算子を宣言します。バイナリ演算子は、2+3
などの2つの値に作用します。優先順位の高い演算子が最初に計算されます。デフォルトの演算子の優先順位は、より高いです
?
...:
Swift 2.xでは100の値)。標準的なSwift演算子の優先順位はここで見つけることができます 。Associativityは、同じ優先順位の演算子間の演算の順序を定義します。左連想演算子は、左から右(ほとんどの演算子のように読取り順序)で計算され、右結合演算子は右から左に計算されます。
演算子は、計算コードに基づいて値を返します。このコードは、入力のタイプを指定するパラメータと、演算子が返す計算値を指定するreturn
キーワードを持つ通常の関数として機能します。
標準スウィフトには指数演算子がないため、単純指数演算子の定義があります。
import Foundation
infix operator ** { associativity left precedence 170 }
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
infix
は、 **
演算子は9**2
ように2つの値の間で動作すると言います。関数は連想を残しているので、 3**3**2
は(3**3)**2
として計算されます。優先順位170
つまり、すべての標準スウィフト操作よりも高い3+2**4
に算出19
の左側の結合性にもかかわらず、 **
。
import Foundation
infix operator **: BitwiseShiftPrecedence
func ** (num: Double, power: Double) -> Double {
return pow(num, power)
}
優先度と結合性を明示的に指定するのではなく、Swift 3.0では、正しい値( <<
、 >>
と同じ)を与えるビルトイン優先グループBitwiseShiftPrecedenceを使用できます。
**:インクリメントとデクリメントは廃止され、Swift 3では削除されます。
辞書のオーバーロード+
現在のところSwiftで辞書を組み合わせる簡単な方法はないので、 ジェネリックを使ってこの機能を追加するには、 +
と+=
演算子をオーバーロードすると便利です。
// Combines two dictionaries together. If both dictionaries contain
// the same key, the value of the right hand side dictionary is used.
func +<K, V>(lhs: [K : V], rhs: [K : V]) -> [K : V] {
var combined = lhs
for (key, value) in rhs {
combined[key] = value
}
return combined
}
// The mutable variant of the + overload, allowing a dictionary
// to be appended to 'in-place'.
func +=<K, V>(inout lhs: [K : V], rhs: [K : V]) {
for (key, value) in rhs {
lhs[key] = value
}
}
スイフト3の時点では、 inout
は引数の型の前に置く必要があります。
func +=<K, V>(lhs: inout [K : V], rhs: [K : V]) { ... }
使用例:
let firstDict = ["hello" : "world"]
let secondDict = ["world" : "hello"]
var thirdDict = firstDict + secondDict // ["hello": "world", "world": "hello"]
thirdDict += ["hello":"bar", "baz":"qux"] // ["hello": "bar", "baz": "qux", "world": "hello"]
可換演算子
CGSizeを乗算するカスタム演算子を追加しましょう
func *(lhs: CGFloat, rhs: CGSize) -> CGSize{
let height = lhs*rhs.height
let width = lhs*rhs.width
return CGSize(width: width, height: height)
}
今これは動作します
let sizeA = CGSize(height:100, width:200)
let sizeB = 1.1 * sizeA //=> (height: 110, width: 220)
しかし、逆に操作しようとすると、エラーが発生します
let sizeC = sizeB * 20 // ERROR
しかし、追加するだけで十分です:
func *(lhs: CGSize, rhs: CGFloat) -> CGSize{
return rhs*lhs
}
オペレータは可換性です。
let sizeA = CGSize(height:100, width:200)
let sizeB = sizeA * 1.1 //=> (height: 110, width: 220)
ビット演算子
Swift Bitwise演算子を使用すると、バイナリ形式の数値に対して演算を実行できます。数字の先頭に0b
付けることで、バイナリリテラルを指定することができます。たとえば、 0b110
は2進数110(10進数6)と等価です。それぞれ1または0は数字のビットです。
ビットごとのNOT ~
:
var number: UInt8 = 0b01101100
let newNumber = ~number
// newNumber is equal to 0b01101100
ここでは、各ビットがその反対に変更されます。明示的に番号を宣言UInt8
数が正である(私たちは例のネガに対処する必要がないように)、それは唯一の8ビットであることを保証します。 0b01101100
がより大きい0b01101100
だった場合、先頭に0があり、これは1に変換され、反転時に有意になります。
var number: UInt16 = 0b01101100
// number equals 0b0000000001101100
// the 0s are not significant
let newNumber = ~number
// newNumber equals 0b1111111110010011
// the 1s are now significant
- 0 - > 1
- 1→0
ビット単位AND &
:
var number = 0b0110
let newNumber = number & 0b1010
// newNumber is equal to 0b0010
ここで、 &
演算子の両側の2進数がそのビット位置に1を含む場合に限り、与えられたビットは1になります。
- 0&0 - > 0
- 0&1→0
- 1&1→1
ビット単位OR |
:
var number = 0b0110
let newNumber = number | 0b1000
// newNumber is equal to 0b1110
ここで、 |
1の少なくとも片側の2進数が1である場合に限り、与えられたビットは1になります|
オペレータはそのビット位置に1を含んでいた。
- 0 | 0→0
- 0 | 1→1
- 1 | 1→1
ビット単位の排他的論理和(排他的論理和) ^
:
var number = 0b0110
let newNumber = number ^ 0b1010
// newNumber is equal to 0b1100
ここで、2つのオペランドのその位置にあるビットが異なる場合に限り、与えられたビットは1になります。
- 0 ^ 0→0
- 0 ^ 1→1
- 1 ^ 1→0
すべてのバイナリ演算では、オペランドの順序が結果に大きな違いはありません。
オーバーフロー演算子
オーバーフローとは、操作によって、指定された数のビットが保持できるビット数よりも大きいか小さいビット数になる場合に発生することを指します。
バイナリ算術が動作する方法のために、あるビットがそのビットに対して大きすぎると、その数は(ビット・サイズのために)可能な限り小さい数にオーバーフローし、そこからカウント・アップを続ける。同様に、数値が小さ過ぎると、可能な限り最大数(ビットサイズ)までアンダーフローし、そこからカウントダウンを続けます。
この動作はしばしば望ましくなく、重大なセキュリティ問題につながる可能性があるため、操作がオーバーフローまたはアンダーフローを引き起こすと、Swift算術演算子+
、 -
、および*
はエラーをスローします。オーバーフローとアンダーフローを明示的に許可するには、代わりに&+
、 &-
、 &*
使用します。
var almostTooLarge = Int.max
almostTooLarge + 1 // not allowed
almostTooLarge &+ 1 // allowed, but result will be the value of Int.min
標準Swiftオペレータの優先順位
より緊密に(高い優先順位)バインドされた演算子が最初にリストされます。
演算子 | 優先グループ(≧3.0) | 優先順位 | 関連性 |
---|---|---|---|
. | ∞ | 左 | |
? 、 ! 、 ++ 、 -- 、 [] 、 () 、 {} | (後置) | ||
! 、 ~ 、 + 、 - 、 ++ 、 -- | (接頭辞) | ||
~> (速い≤2.3) | 255 | 左 | |
<< 、 >> | BitwiseShiftPrecedence | 160 | 無し |
* 、 / 、 % 、 & 、 &* | MultiplicationPrecedence | 150 | 左 |
+ 、 - 、 | 、 ^ 、 &+ 、 &- | AdditionPrecedence | 140 | 左 |
... 、 ..< | RangeFormationPrecedence | 135 | 無し |
is 、 as 、 as? 、 as! | CastingPrecedence | 132 | 左 |
?? | NilCoalescingPrecedence | 131 | 右 |
< 、 <= 、 > 、 >= 、 == 、 != 、 === 、 !== 、 ~= | ComparisonPrecedence | 130 | 無し |
&& | LogicalConjunctionPrecedence | 120 | 左 |
|| | LogicalDisjunctionPrecedence | 110 | 左 |
DefaultPrecedence * | 無し | ||
? ... : | TernaryPrecedence | 100 | 右 |
= 、 += 、 -= 、 *= 、 /= 、 %= 、 <<= 、 >>= 、 &= 、 |= 、 ^= | AssignmentPrecedence | 90 | 権利、譲渡 |
-> | FunctionArrowPrecedence | 右 |
-
DefaultPrecedence
優先順位グループはTernaryPrecedence
よりも上位ですが、残りの演算子と順序はTernaryPrecedence
ます。このグループ以外の優先順位は線形です。
- この表はAppleのAPIリファレンスにも記載されています
- 優先グループの実際の定義はGitHubのソースコードにあります