In addition to the operators described inBasic Operators, Swift provides several advanced operators that perform more complex value manipulation. These include all of the bitwise and bit shifting operators you will be familiar with from C and Objective-C.
除了在之前介绍过的基本运算符,Swift 中还有许多可以对数值进行复杂运算的高级运算符。这些高级运算符包含了在 C 和 Objective-C 中已经被大家所熟知的位运算符和移位运算符。
Unlike arithmetic operators in C, arithmetic operators in Swift do not overflow by default. Overflow behavior is trapped and reported as an error. To opt in to overflow behavior, use Swift’s second set of arithmetic operators that overflow by default, such as the overflow addition operator (&+). All of these overflow operators begin with an ampersand (&).
与 C 语言中的算术运算符不同,Swift 中的算术运算符默认是不会溢出的。所有溢出行为都会被捕获并报告为错误。如果想让系统允许溢出行为,可以选择使用 Swift 中另一套默认支持溢出的运算符,比如溢出加法运算符(&+)。所有的这些溢出运算符都是以&开头的。
When you define your own structures, classes, and enumerations, it can be useful to provide your own implementations of the standard Swift operators for these custom types. Swift makes it easy to provide tailored implementations of these operators and to determine exactly what their behavior should be for each type you create.
自定义结构体、类和枚举时,如果也为它们提供标准 Swift 运算符的实现,将会非常有用。在 Swift 中自定义运算符非常简单,运算符也会针对不同类型使用对应实现。
You’re not limited to the predefined operators. Swift gives you the freedom to define your own custom infix, prefix, postfix, and assignment operators, with custom precedence and associativity values. These operators can be used and adopted in your code like any of the predefined operators, and you can even extend existing types to support the custom operators you define.
我们不用被预定义的运算符所限制。在 Swift 中可以自由地定义中缀、前缀、后缀和赋值运算符,以及相应的优先级与结合性。这些运算符在代码中可以像预定义的运算符一样使用,我们甚至可以扩展已有的类型以支持自定义的运算符。
Bitwise Operators (位运算符)
Bitwise operatorsenable you to manipulate the individual raw data bits within a data structure. They are often used in low-level programming, such as graphics programming and device driver creation. Bitwise operators can also be useful when you work with raw data from external sources, such as encoding and decoding data for communication over a custom protocol.
位运算符可以操作数据结构中每个独立的比特位。它们通常被用在底层开发中,比如图形编程和创建设备驱动。位运算符在处理外部资源的原始数据时也十分有用,比如对自定义通信协议传输的数据进行编码和解码。
Swift supports all of the bitwise operators found in C, as described below.
Swift 支持 C 语言中的全部位运算符,接下来会一一介绍。
Bitwise NOT Operator (按位取反运算符)
Thebitwise NOT operator(~) inverts all bits in a number:
按位取反运算符(~)可以对一个数值的全部比特位进行取反:
The bitwise NOT operator is a prefix operator, and appears immediately before the value it operates on, without any white space:
按位取反运算符是一个前缀运算符,需要直接放在运算的数之前,并且它们之间不能添加任何空格:
let initialBits:UInt8=0b00001111
let invertedBits= ~initialBits// equals 11110000
UInt8integers have eight bits and can store any value between0and255. This example initializes aUInt8integer with the binary value00001111, which has its first four bits set to0, and its second four bits set to1. This is equivalent to a decimal value of15.
UInt8类型的整数有 8 个比特位,可以存储0 ~ 255之间的任意整数。这个例子初始化了一个UInt8类型的整数,并赋值为二进制的00001111,它的前 4 位都为0,后 4 位都为1。这个值等价于十进制的15。
The bitwise NOT operator is then used to create a new constant calledinvertedBits, which is equal toinitialBits, but with all of the bits inverted. Zeros become ones, and ones become zeros. The value ofinvertedBitsis11110000, which is equal to an unsigned decimal value of240.
接着使用按位取反运算符创建了一个名为invertedBits的常量,这个常量的值与全部位取反后的initialBits相等。即所有的0都变成了1,同时所有的1都变成0。invertedBits的二进制值为11110000,等价于无符号十进制数的240。
Bitwise AND Operator (按位与运算符)
Thebitwise AND operator(&) combines the bits of two numbers. It returns a new number whose bits are set to1only if the bits were equal to1inbothinput numbers:
按位与运算符(&)可以对两个数的比特位进行合并。它返回一个新的数,只有当两个数的对应位都为1的时候,新数的对应位才为1:
In the example below, the values offirstSixBitsandlastSixBitsboth have four middle bits equal to1. The bitwise AND operator combines them to make the number00111100, which is equal to an unsigned decimal value of60:
在下面的示例当中,firstSixBits和lastSixBits中间 4 个位的值都为1。按位与运算符对它们进行了运算,得到二进制数值00111100,等价于无符号十进制数的60:
let firstSixBits:UInt8=0b11111100
let lastSixBits:UInt8=0b00111111
let middleFourBits=firstSixBits&lastSixBits// equals 00111100
Bitwise OR Operator (按位或运算符)
Thebitwise OR operator(|) compares the bits of two numbers. The operator returns a new number whose bits are set to1if the bits are equal to1ineitherinput number:
按位或运算符(|)可以对两个数的比特位进行比较。它返回一个新的数,只要两个数的对应位中有任意一个为1时,新数的对应位就为1:
In the example below, the values ofsomeBitsandmoreBitshave different bits set to1. The bitwise OR operator combines them to make the number11111110, which equals an unsigned decimal of254:
在下面的示例中,someBits和moreBits不同的位会被设置为1。接位或运算符对它们进行了运算,得到二进制数值11111110,等价于无符号十进制数的254:
let someBits:UInt8=0b10110010
let moreBits:UInt8=0b01011110
let combinedbits=someBits|moreBits// equals 11111110
Bitwise XOR Operator (按位异或运算符)
Thebitwise XOR operator, or “exclusive OR operator” (^), compares the bits of two numbers. The operator returns a new number whose bits are set to1where the input bits are different and are set to0where the input bits are the same:
按位异或运算符(^)可以对两个数的比特位进行比较。它返回一个新的数,当两个数的对应位不相同时,新数的对应位就为1:
In the example below, the values offirstBitsandotherBitseach have a bit set to1in a location that the other does not. The bitwise XOR operator sets both of these bits to1in its output value. All of the other bits infirstBitsandotherBitsmatch and are set to0in the output value:
在下面的示例当中,firstBits和otherBits都有一个自己的位为1而对方的对应位为0的位。 按位异或运算符将新数的这两个位都设置为1,同时将其它位都设置为0:
let firstBits:UInt8=0b00010100
let otherBits:UInt8=0b00000101
let outputBits=firstBits^otherBits// equals 00010001
Bitwise Left and Right Shift Operators (按位左移、右移运算符)
Thebitwise left shift operator(<<) andbitwise right shift operator(>>) move all bits in a number to the left or the right by a certain number of places, according to the rules defined below.
按位左移运算符(<<)和按位右移运算符(>>)可以对一个数的所有位进行指定位数的左移和右移,但是需要遵守下面定义的规则。
Bitwise left and right shifts have the effect of multiplying or dividing an integer by a factor of two. Shifting an integer’s bits to the left by one position doubles its value, whereas shifting it to the right by one position halves its value.
对一个数进行按位左移或按位右移,相当于对这个数进行乘以 2 或除以 2 的运算。将一个整数左移一位,等价于将这个数乘以 2,同样地,将一个整数右移一位,等价于将这个数除以 2。
Shifting Behavior for Unsigned Integers (无符号整数的移位运算)
The bit-shifting behavior for unsigned integers is as follows:
对无符号整数进行移位的规则如下:
1. Existing bits are moved to the left or right by the requested number of places.
已经存在的位按指定的位数进行左移和右移。
2. Any bits that are moved beyond the bounds of the integer’s storage are discarded.
任何因移动而超出整型存储范围的位都会被丢弃。
3. Zeros are inserted in the spaces left behind after the original bits are moved to the left or right.
用0来填充移位后产生的空白位。
This approach is known as alogical shift.
这种方法称为逻辑移位。
The illustration below shows the results of11111111 << 1(which is11111111shifted to the left by1place), and11111111 >> 1(which is11111111shifted to the right by1place). Blue numbers are shifted, gray numbers are discarded, and orange zeros are inserted:
以下这张图展示了11111111 << 1(即把11111111向左移动1位),和11111111 >> 1(即把11111111向右移动1位)的结果。蓝色的部分是被移位的,灰色的部分是被抛弃的,橙色的部分则是被填充进来的:
Here’s how bit shifting looks in Swift code:
下面的代码演示了 Swift 中的移位运算:
let shift Bits:UInt8=4// 00000100 in binary
shiftBits<<1// 00001000
shiftBits<<2// 00010000
shiftBits<<5// 10000000
shiftBits<<6// 00000000
shiftBits>>2// 00000001
You can use bit shifting to encode and decode values within other data types:
可以使用移位运算对其他的数据类型进行编码和解码:
let pink:UInt32=0xCC6699
letredComponent= (pink&0xFF0000) >>16// redComponent is 0xCC, or 204
letgreenComponent= (pink&0x00FF00) >>8// greenComponent is 0x66, or 102
let blueComponent=pink&0x0000FF// blueComponent is 0x99, or 153
This example uses aUInt32constant calledpinkto store a Cascading Style Sheets color value for the color pink. The CSS color value#CC6699is written as0xCC6699in Swift’s hexadecimal number representation. This color is then decomposed into its red (CC), green (66), and blue (99) components by the bitwise AND operator (&) and the bitwise right shift operator (>>).
这个示例使用了一个命名为pink的UInt32型常量来存储 CSS 中粉色的颜色值。该 CSS 的十六进制颜色值#CC6699,在 Swift 中表示为0xCC6699。然后利用按位与运算符(&)和按位右移运算符(>>)从这个颜色值中分解出红(CC)、绿(66)以及蓝(99)三个部分。
The red component is obtained by performing a bitwise AND between the numbers0xCC6699and0xFF0000. The zeros in0xFF0000effectively “mask” the second and third bytes of0xCC6699, causing the6699to be ignored and leaving0xCC0000as the result.
红色部分是通过对0xCC6699和0xFF0000进行按位与运算后得到的。0xFF0000中的0部分“掩盖”了OxCC6699中的第二、第三个字节,使得数值中的6699被忽略,只留下0xCC0000。
This number is then shifted 16 places to the right (>> 16). Each pair of characters in a hexadecimal number uses 8 bits, so a move 16 places to the right will convert0xCC0000into0x0000CC. This is the same as0xCC, which has a decimal value of204.
然后,再将这个数按向右移动 16 位(>> 16)。十六进制中每两个字符表示 8 个比特位,所以移动 16 位后0xCC0000就变为0x0000CC。这个数和0xCC是等同的,也就是十进制数值的204。
Similarly, the green component is obtained by performing a bitwise AND between the numbers0xCC6699and0x00FF00, which gives an output value of0x006600. This output value is then shifted eight places to the right, giving a value of0x66, which has a decimal value of102.
同样的,绿色部分通过对0xCC6699和0x00FF00进行按位与运算得到0x006600。然后将这个数向右移动 8 位,得到0x66,也就是十进制数值的102。
Finally, the blue component is obtained by performing a bitwise AND between the numbers0xCC6699and0x0000FF, which gives an output value of0x000099. There’s no need to shift this to the right, as0x000099already equals0x99, which has a decimal value of153.
最后,蓝色部分通过对0xCC6699和0x0000FF进行按位与运算得到0x000099。这里不需要再向右移位,所以结果为0x99,也就是十进制数值的153。
Shifting Behavior for Signed Integers (有符号整数的移位运算)
The shifting behavior is more complex for signed integers than for unsigned integers, because of the way signed integers are represented in binary. (The examples below are based on 8-bit signed integers for simplicity, but the same principles apply for signed integers of any size.)
对比无符号整数,有符号整数的移位运算相对复杂得多,这种复杂性源于有符号整数的二进制表现形式。(为了简单起见,以下的示例都是基于 8 比特位的有符号整数的,但是其中的原理对任何位数的有符号整数都是通用的。)
Signed integers use their first bit (known as thesign bit) to indicate whether the integer is positive or negative. A sign bit of0means positive, and a sign bit of1means negative.
有符号整数使用第 1 个比特位(通常被称为符号位)来表示这个数的正负。符号位为0代表正数,为1代表负数。
The remaining bits (known as thevalue bits) store the actual value. Positive numbers are stored in exactly the same way as for unsigned integers, counting upwards from0. Here’s how the bits inside anInt8look for the number4:
其余的比特位(通常被称为数值位)存储了实际的值。有符号正整数和无符号数的存储方式是一样的,都是从0开始算起。这是值为4的Int8型整数的二进制位表现形式:
The sign bit is0(meaning “positive”), and the seven value bits are just the number4, written in binary notation.
符号位为0,说明这是一个正数,另外 7 位则代表了十进制数值4的二进制表示。
Negative numbers, however, are stored differently. They are stored by subtracting their absolute value from2to the power ofn, wherenis the number of value bits. An eight-bit number has seven value bits, so this means2to the power of7, or128.
负数的存储方式略有不同。它存储的值的绝对值等于2的n次方减去它的实际值(也就是数值位表示的值),这里的n为数值位的比特位数。一个 8 比特位的数有 7 个比特位是数值位,所以是2的7次方,即128。
Here’s how the bits inside anInt8look for the number-4:
这是值为-4的Int8型整数的二进制位表现形式:
This time, the sign bit is1(meaning “negative”), and the seven value bits have a binary value of124(which is128 - 4):
这次的符号位为1,说明这是一个负数,另外 7 个位则代表了数值124(即128 - 4)的二进制表示:
This encoding for negative numbers is known as atwo’s complementrepresentation. It may seem an unusual way to represent negative numbers, but it has several advantages.
负数的表示通常被称为二进制补码表示。用这种方法来表示负数乍看起来有点奇怪,但它有几个优点。
First, you can add-1to-4, simply by performing a standard binary addition of all eight bits (including the sign bit), and discarding anything that doesn’t fit in the eight bits once you’re done:
首先,如果想对-1和-4进行加法运算,我们只需要将这两个数的全部 8 个比特位进行相加,并且将计算结果中超出 8 位的数值丢弃:
Second, the two’s complement representation also lets you shift the bits of negative numbers to the left and right like positive numbers, and still end up doubling them for every shift you make to the left, or halving them for every shift you make to the right. To achieve this, an extra rule is used when signed integers are shifted to the right: When you shift signed integers to the right, apply the same rules as for unsigned integers, but fill any empty bits on the left with thesign bit, rather than with a zero.
其次,使用二进制补码可以使负数的按位左移和右移运算得到跟正数同样的效果,即每向左移一位就将自身的数值乘以 2,每向右一位就将自身的数值除以 2。要达到此目的,对有符号整数的右移有一个额外的规则:当对整数进行按位右移运算时,遵循与无符号整数相同的规则,但是对于移位产生的空白位使用符号位进行填充,而不是用0。
This action ensures that signed integers have the same sign after they are shifted to the right, and is known as anarithmetic shift.
这个行为可以确保有符号整数的符号位不会因为右移运算而改变,这通常被称为算术移位。
Because of the special way that positive and negative numbers are stored, shifting either of them to the right moves them closer to zero. Keeping the sign bit the same during this shift means that negative integers remain negative as their value moves closer to zero.
由于正数和负数的特殊存储方式,在对它们进行右移的时候,会使它们越来越接近0。在移位的过程中保持符号位不变,意味着负整数在接近0的过程中会一直保持为负。
Overflow Operators (溢出运算符)
If you try to insert a number into an integer constant or variable that cannot hold that value, by default Swift reports an error rather than allowing an invalid value to be created. This behavior gives extra safety when you work with numbers that are too large or too small.
在默认情况下,当向一个整数赋予超过它容量的值时,Swift 默认会报错,而不是生成一个无效的数。这个行为为我们在运算过大或着过小的数的时候提供了额外的安全性。
For example, theInt16integer type can hold any signed integer between-32768and32767. Trying to set anInt16constant or variable to a number outside of this range causes an error:
例如,Int16型整数能容纳的有符号整数范围是-32768到32767,当为一个Int16型变量赋的值超过这个范围时,系统就会报错:
var potentialOverflow=Int16.max
// potentialOverflow equals 32767, which is the maximum value an Int16 can hold
potential Overflow+=1
// this causes an error
Providing error handling when values get too large or too small gives you much more flexibility when coding for boundary value conditions.
为过大或者过小的数值提供错误处理,能让我们在处理边界值时更加灵活。
However, when you specifically want an overflow condition to truncate the number of available bits, you can opt in to this behavior rather than triggering an error. Swift provides three arithmeticoverflow operatorsthat opt in to the overflow behavior for integer calculations. These operators all begin with an ampersand (&):
然而,也可以选择让系统在数值溢出的时候采取截断处理,而非报错。可以使用 Swift 提供的三个溢出运算符来让系统支持整数溢出运算。这些运算符都是以&开头的:
1. Overflow addition (&+)
溢出加法&+
2. Overflow subtraction (&-)
溢出减法&-
3. Overflow multiplication (&*)
溢出乘法&*
Value Overflow (数值溢出)
Numbers can overflow in both the positive and negative direction.
数值有可能出现上溢或者下溢。
Here’s an example of what happens when an unsigned integer is allowed to overflow in the positive direction, using the overflow addition operator (&+):
这个示例演示了当我们对一个无符号整数使用溢出加法(&+)进行上溢运算时会发生什么:
var unsigned Overflow=UInt8.max
// unsignedOverflow equals 255, which is the maximum value a UInt8 can hold
unsigned Overflow=unsignedOverflow&+1
// unsignedOverflow is now equal to 0
The variableunsignedOverflowis initialized with the maximum value aUInt8can hold (255, or11111111in binary). It is then incremented by1using the overflow addition operator (&+). This pushes its binary representation just over the size that aUInt8can hold, causing it to overflow beyond its bounds, as shown in the diagram below. The value that remains within the bounds of theUInt8after the overflow addition is00000000, or zero.
unsignedOverflow被初始化为UInt8所能容纳的最大整数(255,以二进制表示即11111111)。然后使用了溢出加法运算符(&+)对其进行加1运算。这使得它的二进制表示正好超出UInt8所能容纳的位数,也就导致了数值的溢出,如下图所示。数值溢出后,留在UInt8边界内的值是00000000,也就是十进制数值的0。
Something similar happens when an unsigned integer is allowed to overflow in the negative direction. Here’s an example using the overflow subtraction operator (&-):
同样地,当我们对一个无符号整数使用溢出减法(&-)进行下溢运算时也会产生类似的现象:
var unsignedOverflow=UInt8.min
// unsignedOverflow equals 0, which is the minimum value a UInt8 can hold
unsigned Overflow=unsignedOverflow&-1
// unsignedOverflow is now equal to 255
The minimum value that aUInt8can hold is zero, or00000000in binary. If you subtract1from00000000using the overflow subtraction operator (&-), the number will overflow and wrap around to11111111, or255in decimal.
UInt8型整数能容纳的最小值是0,以二进制表示即00000000。当使用溢出减法运算符对其进行减1运算时,数值会产生下溢并被截断为11111111, 也就是十进制数值的255。
Overflow also occurs for signed integers. All addition and subtraction for signed integers is performed in bitwise fashion, with the sign bit included as part of the numbers being added or subtracted, as described inBitwise Left and Right Shift Operators.
溢出也会发生在有符号整型数值上。在对有符号整型数值进行溢出加法或溢出减法运算时,符号位也需要参与计算,正如按位左移、右移运算符所描述的。
var signedOverflow=Int8.min
// signedOverflow equals -128, which is the minimum value an Int8 can hold
signedOverflow=signedOverflow&-1
// signedOverflow is now equal to 127
The minimum value that anInt8can hold is-128, or10000000in binary. Subtracting1from this binary number with the overflow operator gives a binary value of01111111, which toggles the sign bit and gives positive127, the maximum positive value that anInt8can hold.
Int8型整数能容纳的最小值是-128,以二进制表示即10000000。当使用溢出减法运算符对其进行减1运算时,符号位被翻转,得到二进制数值01111111,也就是十进制数值的127,这个值也是Int8型整数所能容纳的最大值。
For both signed and unsigned integers, overflow in the positive direction wraps around from the maximum valid integer value back to the minimum, and overflow in the negative direction wraps around from the minimum value to the maximum.
对于无符号与有符号整型数值来说,当出现上溢时,它们会从数值所能容纳的最大数变成最小的数。同样地,当发生下溢时,它们会从所能容纳的最小数变成最大的数。
Precedence and Associativity (优先级和结合性)
Operatorprecedencegives some operators higher priority than others; these operators are applied first.
运算符的优先级使得一些运算符优先于其他运算符,高优先级的运算符会先被计算。
Operatorassociativitydefines how operators of the same precedence are grouped together—either grouped from the left, or grouped from the right. Think of it as meaning “they associate with the expression to their left,” or “they associate with the expression to their right.”
结合性定义了相同优先级的运算符是如何结合的,也就是说,是与左边结合为一组,还是与右边结合为一组。可以将这意思理解为“它们是与左边的表达式结合的”或者“它们是与右边的表达式结合的”。
It is important to consider each operator’s precedence and associativity when working out the order in which a compound expression will be calculated. For example, operator precedence explains why the following expression equals17.
在复合表达式的运算顺序中,运算符的优先级和结合性是非常重要的。举例来说,运算符优先级解释了为什么下面这个表达式的运算结果会是17。
2+3%4*5
// this equals 17
If you read strictly from left to right, you might expect the expression to be calculated as follows:
如果完全从左到右进行运算,则运算的过程是这样的:
2plus3 equals5
5remainder4 equals1
1times5 equals5
However, the actual answer is17, not5. Higher-precedence operators are evaluated before lower-precedence ones. In Swift, as in C, the remainder operator (%) and the multiplication operator (*) have a higher precedence than the addition operator (+). As a result, they are both evaluated before the addition is considered.
但是正确答案是17而不是5。优先级高的运算符要先于优先级低的运算符进行计算。与 C 语言类似,在 Swift 中,乘法运算符(*)与取余运算符(%)的优先级高于加法运算符(+)。因此,它们的计算顺序要先于加法运算。
However, remainder and multiplication have thesameprecedence as each other. To work out the exact evaluation order to use, you also need to consider their associativity. Remainder and multiplication both associate with the expression to their left. Think of this as adding implicit parentheses around these parts of the expression, starting from their left:
而乘法与取余的优先级相同。这时为了得到正确的运算顺序,还需要考虑结合性。乘法与取余运算都是左结合的。可以将这考虑成为这两部分表达式都隐式地加上了括号:
2+ ((3%4) *5)
(3 % 4)is3, so this is equivalent to:
(3 % 4)等于3,所以表达式相当于:
2+ (3*5)
(3 * 5)is15, so this is equivalent to:
3 * 5等于15,所以表达式相当于:
2+15
This calculation yields the final answer of17.
因此计算结果为17。
For a complete list of Swift operator precedences and associativity rules, seeExpressions. For information about the operators provided by the Swift standard library, seeSwift Standard Library Operators Reference.
如果想查看完整的 Swift 运算符优先级和结合性规则,请参考表达式。如果想查看 Swift 标准库提供所有的运算符,请查看Swift Standard Library Operators Reference。
NOTE
Swift’s operator precedences and associativity rules are simpler and more predictable than those found in C and Objective-C. However, this means that they are not exactly the same as in C-based languages. Be careful to ensure that operator interactions still behave in the way you intend when porting existing code to Swift.
相对 C 语言和 Objective-C 来说,Swift 的运算符优先级和结合性规则更加简洁和可预测。但是,这也意味着它们相较于 C 语言及其衍生语言并不是完全一致的。在对现有的代码进行移植的时候,要注意确保运算符的行为仍然符合你的预期。
Operator Methods (运算符函数)
Classes and structures can provide their own implementations of existing operators. This is known asoverloadingthe existing operators.
类和结构体可以为现有的运算符提供自定义的实现,这通常被称为运算符重载。
The example below shows how to implement the arithmetic addition operator (+) for a custom structure. The arithmetic addition operator is abinary operatorbecause it operates on two targets and is said to beinfixbecause it appears in between those two targets.
下面的例子展示了如何为自定义的结构体实现加法运算符(+)。算术加法运算符是一个双目运算符,因为它可以对两个值进行运算,同时它还是中缀运算符,因为它出现在两个值中间。
The example defines aVector2Dstructure for a two-dimensional position vector(x, y), followed by a definition of anoperator methodto add together instances of theVector2Dstructure:
例子中定义了一个名为Vector2D的结构体用来表示二维坐标向量(x, y),紧接着定义了一个可以对两个Vector2D结构体进行相加的运算符函数:
struct Vector2D{
var x=0.0,y=0.0
}
extension Vector2D{
static func + (left:Vector2D,right:Vector2D) ->Vector2D{
return Vector2D(x:left.x+right.x,y:left.y+right.y)
}
}
The operator method is defined as a type method onVector2D, with a method name that matches the operator to be overloaded (+). Because addition isn’t part of the essential behavior for a vector, the type method is defined in an extension ofVector2Drather than in the main structure declaration ofVector2D. Because the arithmetic addition operator is a binary operator, this operator method takes two input parameters of typeVector2Dand returns a single output value, also of typeVector2D.
该运算符函数被定义为Vector2D上的一个类方法,并且函数的名字与它要进行重载的+名字一致。因为加法运算并不是一个向量必需的功能,所以这个类方法被定义在Vector2D的一个扩展中,而不是Vector2D结构体声明内。而算术加法运算符是双目运算符,所以这个运算符函数接收两个类型为Vector2D的参数,同时有一个Vector2D类型的返回值。
In this implementation, the input parameters are namedleftandrightto represent theVector2Dinstances that will be on the left side and right side of the+operator. The method returns a newVector2Dinstance, whosexandyproperties are initialized with the sum of thexandyproperties from the twoVector2Dinstances that are added together.
在这个实现中,输入参数分别被命名为left和right,代表在+运算符左边和右边的两个Vector2D实例。函数返回了一个新的Vector2D实例,这个实例的x和y分别等于作为参数的两个实例的x和y的值之和。
The type method can be used as an infix operator between existingVector2Dinstances:
这个函数被定义成全局的,而不是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 is a Vector2D instance with values of (5.0, 5.0)
This example adds together the vectors(3.0, 1.0)and(2.0, 4.0)to make the vector(5.0, 5.0), as illustrated below.
这个例子实现两个向量(3.0,1.0)和(2.0,4.0)的相加,并得到新的向量(5.0,5.0)。这个过程如下图示:
Prefix and Postfix Operators (前缀和后缀运算符)
The example shown above demonstrates a custom implementation of a binary infix operator. Classes and structures can also provide implementations of the standardunary operators. Unary operators operate on a single target. They areprefixif they precede their target (such as-a) andpostfixoperators if they follow their target (such asb!).
上个例子演示了一个双目中缀运算符的自定义实现。类与结构体也能提供标准单目运算符的实现。单目运算符只运算一个值。当运算符出现在值之前时,它就是前缀的(例如-a),而当它出现在值之后时,它就是后缀的(例如b!)。
You implement a prefix or postfix unary operator by writing theprefixorpostfixmodifier before thefunckeyword when declaring the operator method:
要实现前缀或者后缀运算符,需要在声明运算符函数的时候在func关键字之前指定prefix或者postfix修饰符:
extension Vector2D{
static prefix func- (vector:Vector2D) ->Vector2D{
return Vector2D(x: -vector.x,y: -vector.y)
}
}
The example above implements the unary minus operator (-a) forVector2Dinstances. The unary minus operator is a prefix operator, and so this method has to be qualified with theprefixmodifier.
这段代码为Vector2D类型实现了单目负号运算符。由于该运算符是前缀运算符,所以这个函数需要加上prefix修饰符。
For simple numeric values, the unary minus operator converts positive numbers into their negative equivalent and vice versa. The corresponding implementation forVector2Dinstances performs this operation on both thexandyproperties:
对于简单数值,单目负号运算符可以对它们的正负性进行改变。对于Vector2D来说,该运算将其x和y属性的正负性都进行了改变:
let positive=Vector2D(x:3.0,y:4.0)
let negative= -positive
// negative is a Vector2D instance with values of (-3.0, -4.0)
let alsoPositive= -negative
// alsoPositive is a Vector2D instance with values of (3.0, 4.0)
Compound Assignment Operators (复合赋值运算符)
Compound assignment operatorscombine assignment (=) with another operation. For example, the addition assignment operator (+=) combines addition and assignment into a single operation. You mark a compound assignment operator’s left input parameter type asinout, because the parameter’s value will be modified directly from within the operator method.
复合赋值运算符将赋值运算符(=)与其它运算符进行结合。例如,将加法与赋值结合成加法赋值运算符(+=)。在实现的时候,需要把运算符的左参数设置成inout类型,因为这个参数的值会在运算符函数内直接被修改。
The example below implements an addition assignment operator method forVector2Dinstances:
下面的示例为Vector2Dinstances实现了一个加法赋值运算符方法:
extension Vector2D{
static func += (left:inoutVector2D,right:Vector2D) {
lef t=left+right
}
}
Because an addition operator was defined earlier, you don’t need to reimplement the addition process here. Instead, the addition assignment operator method takes advantage of the existing addition operator method, and uses it to set the left value to be the left value plus the right value:
因为加法运算在之前已经定义过了,所以在这里无需重新定义。在这里可以直接利用现有的加法运算符函数,用它来对左值和右值进行相加,并再次赋值给左值:
var original=Vector2D(x:1.0,y:2.0)
let vectorToAdd=Vector2D(x:3.0,y:4.0)
original+=vectorToAdd
// original now has values of (4.0, 6.0)
NOTE
It is not possible to overload the default assignment operator (=). Only the compound assignment operators can be overloaded. Similarly, the ternary conditional operator (a ? b : c) cannot be overloaded.
不能对默认的赋值运算符(=)进行重载。只有组合赋值运算符可以被重载。同样地,也无法对三目条件运算符 (a ? b : c) 进行重载。
Equivalence Operators (等价运算符)
Custom classes and structures do not receive a default implementation of theequivalence operators, known as the “equal to” operator (==) and “not equal to” operator (!=). It is not possible for Swift to guess what would qualify as “equal” for your own custom types, because the meaning of “equal” depends on the roles that those types play in your code.
自定义的类和结构体没有对等价运算符进行默认实现,等价运算符通常被称为“相等”运算符(==)与“不等”运算符(!=)。对于自定义类型,Swift 无法判断其是否“相等”,因为“相等”的含义取决于这些自定义类型在你的代码中所扮演的角色。
To use the equivalence operators to check for equivalence of your own custom type, provide an implementation of the operators in the same way as for other infix operators:
为了使用等价运算符能对自定义的类型进行判等运算,需要为其提供自定义实现,实现的方法与其它中缀运算符一样:
extension Vector2D{
static func== (left:Vector2D,right:Vector2D) ->Bool{
return (left.x==right.x) && (left.y==right.y)
}
static func!= (left:Vector2D,right:Vector2D) ->Bool{
return !(left==right)
}
}
The above example implements an “equal to” operator (==) to check if twoVector2Dinstances have equivalent values. In the context ofVector2D, it makes sense to consider “equal” as meaning “both instances have the samexvalues andyvalues”, and so this is the logic used by the operator implementation. The example also implements the “not equal to” operator (!=), which simply returns the inverse of the result of the “equal to” operator.
上述代码实现了“相等”运算符(==)来判断两个Vector2D实例是否相等。对于Vector2D类型来说,“相等”意味着“两个实例的x属性和y属性都相等”,这也是代码中用来进行判等的逻辑。示例里同时也实现了“不等”运算符(!=),它简单地将“相等”运算符的结果进行取反后返回。
You can now use these operators to check whether twoVector2Dinstances are equivalent:
现在我们可以使用这两个运算符来判断两个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.")
}
// Prints "These two vectors are equivalent."
Custom Operators (自定义运算符)
You can declare and implement your owncustom operatorsin addition to the standard operators provided by Swift. For a list of characters that can be used to define custom operators, seeOperators.
除了实现标准运算符,在 Swift 中还可以声明和实现自定义运算符。可以用来自定义运算符的字符列表请参考运算符。
New operators are declared at a global level using theoperatorkeyword, and are marked with theprefix,infixorpostfixmodifiers:
新的运算符要使用operator关键字在全局作用域内进行定义,同时还要指定prefix、infix或者postfix修饰符:
prefix operator +++
The example above defines a new prefix operator called+++. This operator does not have an existing meaning in Swift, and so it is given its own custom meaning below in the specific context of working withVector2Dinstances. For the purposes of this example,+++is treated as a new “prefix doubling” operator. It doubles thexandyvalues of aVector2Dinstance, by adding the vector to itself with the addition assignment operator defined earlier. To implement the+++operator, you add a type method called+++toVector2Das follows:
上面的代码定义了一个新的名为+++的前缀运算符。对于这个运算符,在 Swift 中并没有意义,因此我们针对Vector2D的实例来定义它的意义。对这个示例来讲,+++被实现为“前缀双自增”运算符。它使用了前面定义的复合加法运算符来让矩阵对自身进行相加,从而让Vector2D实例的x属性和y属性的值翻倍。实现+++运算符的方式如下:
extension Vector2D{
static prefix func+++ (vector:inoutVector2D) ->Vector2D{
vector += vector
return vector
}
}
var toBeDoubled=Vector2D(x:1.0,y:4.0)
let afterDoubling= +++toBeDoubled
// toBeDoubled now has values of (2.0, 8.0)
// afterDoubling also has values of (2.0, 8.0)
Precedence for Custom Infix Operators (自定义中缀运算符的优先级)
Custom infix operators each belong to a precedence group. A precedence group specifies an operator’s precedence relative to other infix operators, as well as the operator’s associativity. SeePrecedence and Associativityfor an explanation of how these characteristics affect an infix operator’s interaction with other infix operators.
每个自定义中缀运算符都属于某个优先级组。这个优先级组指定了这个运算符和其他中缀运算符的优先级和结合性。优先级和结合性中详细阐述了这两个特性是如何对中缀运算符的运算产生影响的。
A custom infix operator that is not explicitly placed into a precedence group is given a default precedence group with a precedence immediately higher than the precedence of the ternary conditional operator.
而没有明确放入优先级组的自定义中缀运算符会放到一个默认的优先级组内,其优先级高于三元运算符。
The following example defines a new custom infix operator called+-, which belongs to the precedence groupAdditionPrecedence:
以下例子定义了一个新的自定义中缀运算符+-,此运算符属于AdditionPrecedence优先组:
infix operator +-:AdditionPrecedence
extension Vector2D{
static func +- (left:Vector2D,right:Vector2D) ->Vector2D{
return Vector2D(x:left.x+right.x,y:left.y-right.y)
}
}
let firstVector=Vector2D(x:1.0,y:2.0)
let secondVector=Vector2D(x:3.0,y:4.0)
let plusMinusVector=firstVector+-secondVector
// plusMinusVector is a Vector2D instance with values of (4.0, -2.0)
This operator adds together thexvalues of two vectors, and subtracts theyvalue of the second vector from the first. Because it is in essence an “additive” operator, it has been given the same precedence group as additive infix operators such as+and-. For a complete list of the operator precedence groups and associativity settings, for the operators provided by the Swift standard library, seeSwift Standard Library Operators Reference. For more information about precedence groups and to see the syntax for defining your own operators and precedence groups, seeOperator Declaration.
这个运算符把两个向量的x值相加,同时用第一个向量的y值减去第二个向量的y值。因为它本质上是属于“相加型”运算符,所以将它放置+和-等默认的中缀“相加型”运算符相同的优先级组中。关于 Swift 标准库提供的运算符,以及完整的运算符优先级组和结合性设置,请参考Swift Standard Library Operators Reference。而更多关于优先级组以及自定义操作符和优先级组的语法,请参考运算符声明
NOTE
You do not specify a precedence when defining a prefix or postfix operator. However, if you apply both a prefix and a postfix operator to the same operand, the postfix operator is applied first.
当定义前缀与后缀运算符的时候,我们并没有指定优先级。然而,如果对同一个值同时使用前缀与后缀运算符,则后缀运算符会先参与运算。