没有运营商的计划会是什么?类,命名空间,条件,循环和命名空间的混合表示什么都没有。git
运营商是一个程序的工做。它们是可执行文件的执行; 每一个过程的目的论驱动因素。程序员
若是咱们要剖析一个表达式 - 好比说1 + 2
- 并将其分解为组成部分,咱们会找到一个运算符和两个操做数:github
1 | + | 2 |
---|---|---|
左操做数 | 操做者 | 右操做数 |
表达式用单个扁平代码表示,编译器从中构造 AST或抽象语法树:面试
对于复合表达式,如1 + 2 * 3
或5 - 2 + 3
,编译器使用运算符优先级和关联性的规则 将表达式解析为单个值。编程
运算符优先级规则与您在小学中学习的规则 相似,决定了评估不一样类型运算符的顺序。在这种状况下,乘法的优先级高于加法,所以2 * 3
首先求值。swift
1 | + | (2 * 3) |
---|---|---|
左操做数 | 操做者 | 右操做数 |
关联性肯定解析具备相同优先级的运算符的顺序。若是运算符是左关联的,则首先计算左侧的操做数:( (5 - 2) + 3
); 若是是右关联的,那么首先评估右侧算子:5 - (2 + 3)
。数组
算术运算符是左关联的,所以5 - 2 + 3
求值为6
。bash
(5 - 2) | + | 3 |
---|---|---|
左操做数 | 操做者 | 右操做数 |
Swift标准库包括程序员可能指望来自C系列中另外一种语言的大多数运算符,以及一些方便的添加,如nil-coalescing operator(??
)和模式匹配operator(~=
),以及运算符类型检查(is
),型铸造(as
,as?
,as!
)以及造成开放或封闭范围(...
,..<
)。编程语言
Swift 对二元运算符使用中 缀
表示法(而不是反向波兰表示法)。中缀运算符根据其关联性和优先级按如下顺序分组以下:函数
<< | 按位左移 |
---|---|
>> | 按位右移 |
* | 乘 | / | 划分 | % | 剩余 | ||
---|---|---|---|---|---|---|---|
&* | 乘以,忽略溢出 | &/ | 划分,忽略溢出 | &% | 剩余,忽略溢出 | ||
& | 按位AND |
+ | 加 | - | 减去 | &+ | 添加溢出 |
---|---|---|---|---|---|
& - | 减去溢出 |
![]() |
按位OR | ^ | 按位异或 |
.. < | 半开放范围 | ... | 封闭的范围 |
---|
是 | 键入检查 | 如 | 输入 |
---|
?? | 没有合并 |
---|
< | 少于 | <= | 小于等于 | |
---|---|---|---|---|
> | 比...更棒 | > = | 大于或等于 | |
== | 等于 | != | 不相等 | |
=== | 相同 | !== | 不同 | |
〜= | 模式匹配 |
&& | 逻辑和 |
---|
![]() |
逻辑或 |
---|
= | 分配 | * = | 乘以并分配 | / = | 划分并分配 | ||
---|---|---|---|---|---|---|---|
%= | 剩余并分配 | + = | 添加并分配 | - = | 减去并分配 | ||
<< = | 左移位和分配 | >> = | 右移位和分配 | &= | 按位AND和赋值 | ||
^ = | 按位异或并分配 |
![]() |
按位OR和赋值 | && = | 逻辑AND和分配 | ||
![]() |
逻辑OR和赋值 |
运算符优先级组最初使用数字优先级定义。例如,乘法运算符定义的优先级值为150,所以它们在加法运算符以前进行求值,这些运算符定义了优先级值140。
在Swift 3中,运算符更改成经过部分排序来定义优先级以造成DAG
或有向非循环图
。有关此更改的详细信息,请阅读Swift Evolution提议 SE-0077改进的操做员声明。
除了采用两个操做数的二元运算符以外,还有一元运算符,它采用单个操做数。
前缀运算符在它们运行的表达式以前出现。Swift默认定义了一些:
+
:一元加-
:一元减去!
:逻辑不~
:按位NOT例如,!
前缀运算符否认其操做数的逻辑值,-
前缀运算符否认其操做数的数值。
!true // false
-(1.0 + 2.0) // -3.0
复制代码
在Swift 3中删除了递增/递减(++
/ --
)运算符。这是 在语言做为开源发布后做为Swift Evolution
过程的一部分进行的第一次更改之一 。在提案中,Chris Lattner
描述了这些运算符如何使人困惑,并争论为何语言中不须要它们。
一元运算符也能够在它们的操做数以后出现,就像postfix变种同样。这些不太常见; Swift标准库仅声明开放式范围后缀运算符...
。
let fruits = ["🍎", "🍌", "🍐", "🍊", "🍋"]
fruits[3...] // ["🍊", "🍋"]
复制代码
三元?:
运算符很特殊。它须要三个操做数和函数,如单行if-else
语句:评估左侧的逻辑条件,?
并:
根据结果在左侧或右侧生成表达式:
true ? "Yes" : "No" // "Yes"
复制代码
在Swift中, 定义低于 和高于。可是,通常来讲,最好保持三元运算符的使用简单(或彻底避免使用它们)。Ternary<wbr style="box-sizing: border-box;">Precedence``Default<wbr style="box-sizing: border-box;">Precedence``Assignment<wbr style="box-sizing: border-box;">Precedence
声明运算符后,它能够与类型方法或顶级函数关联。当操做员能够根据操做数的类型解析不一样的函数时,咱们说运算符是过载的。
能够在+
运营商处找到最重要的超载示例。在许多语言中,+
可用于1 + 2 => 3
对数组和其余集合([1] + [2] => [1, 2]
)执行算术加法()或链接。
开发人员能够经过使用适当的参数数量和类型为运算符符号声明新函数来重载标准运算符。
例如,要重载*
运算符以重复String
指定的次数,您将声明如下顶级函数:
func * (lhs: String, rhs: Int) -> String {
guard rhs > 0 else {
return ""
}
return String(repeating: lhs, count: rhs)
}
"hello" * 3 // hellohellohello
复制代码
然而,这种语言使用是有争议的。(任何C ++开发人员都很是渴望用恐怖故事来谴责你,这可能形成非肯定性的破坏)
请考虑如下声明:
[1, 2] + [3, 4] // [1, 2, 3, 4]
复制代码
默认状况下,+
运算符链接两个数组的元素,并使用通用函数定义实现。
若是要声明一个专用函数,该函数重载+
for Double
values 数组以执行成员添加,它将覆盖先前的链接行为:
// 👿
func + (lhs: [Double], rhs: [Double]) -> [Double] {
return zip(lhs, rhs).map(+)
}
[1.0, 3.0, 5.0] + [2.0, 4.0, 6.0] // [3.0, 7.0, 11.0]
复制代码
这就是运算符重载的原罪: 模糊的语义。
这+
对数字有用 - 这就是数学。可是,若是你真的想到它, 为何要将两个字符串链接在一块儿呢?1 + 2
不是12
(Javascript
除外)。这真的很直观吗?...或只是熟悉。
在决定是否使现有运算符超载时要记住一些事项。
相比之下,PHP .
用于字符串链接,而SQL用于||
; Objective-C自己没有运算符,但会附加带有空格的连续字符串文字。
Swift最使人兴奋的功能之一(虽然也有争议)是定义自定义运算符
的能力。
考虑使用**
许多编程语言中的指数运算符,可是从Swift中找不到。它将左手数字提高到右手数字的幂。(^
一般用于上标的符号已由 按位XOR
运算符使用)。
Exponentiation具备比乘法更高的运算符优先级,而且因为Swift没有咱们可使用的内置优先级组,咱们首先须要本身声明一个:
precedencegroup ExponentiationPrecedence {
associativity: right
higherThan: MultiplicationPrecedence
}
复制代码
如今咱们能够声明运算符自己:
infix operator ** : ExponentiationPrecedence
复制代码
最后,咱们使用new运算符实现顶级函数:
import Darwin
func ** (lhs: Double, rhs: Double) -> Double {
return pow(lhs, rhs)
}
2 ** 3 // 8
复制代码
咱们须要导入Darwin模块来访问标准数学函数pow(_:_:)
。(或者,咱们能够导入Foundation而不是相同的效果。)
建立自定义运算符时,请考虑提供变异变量:
infix operator **= : AssignmentPrecedence
func **= (lhs: inout Double, rhs: Double) {
lhs = pow(lhs, rhs)
}
var n: Double = 10
n **= 1 + 2 // n = 1000
复制代码
自定义操做员可以使用的字符的组合 /
,=
,-
,+
,!
,*
,%
,<
,>
,&
,|
,^
,或~
,并在找到的任何字符 数学运算符的Unicode块,等等。
这使得可使用单个√
前缀运算符取数字的平方根:
import Darwin
prefix operator √
prefix func √ (_ value: Double) -> Double {
return sqrt(value)
}
√4 // 2
复制代码
或者考虑±
运算符,它能够用做中缀或前缀运算符来返回具备和和差的元组:
infix operator ± : AdditionPrecedence
func ± <T: Numeric>(lhs: T, rhs: T) -> (T, T) {
return (lhs + rhs, lhs - rhs)
}
prefix operator ±
prefix func ± <T: Numeric>(_ value: T) -> (T, T) {
return 0 ± value
}
2 ± 3 // (5, -1)
±4 // (4, -4)
复制代码
有关在Swift中使用数学符号的函数的更多示例,请查看Euler。
定制操做员很难打字,所以难以使用,因此要用异国情调的符号来克制。代码应该键入,而不是复制粘贴。
在您本身的代码中覆盖或定义新运算符时,请确保遵循如下准则:
+=
for +
)