ios 知识点iOS 开发每天分享优质文章Swift好文收藏

Swift运算符

2019-06-20  本文已影响176人  iOS_小久

没有运营商的计划会是什么?类,命名空间,条件,循环和命名空间的混合表示什么都没有。

运营商是一个程序的工作。它们是可执行文件的执行; 每个过程的目的论驱动因素。

小编这里推荐一个群:691040931 里面有大量的书籍和面试资料哦有技术的来闲聊 没技术的来学习

运算符优先级和关联性

如果我们要剖析一个表达式 - 比如说1 + 2- 并将其分解为组成部分,我们会找到一个运算符和两个操作数:

1 + 2
左操作数 操作者 右操作数

表达式用单个扁平代码表示,编译器从中构造 AST或抽象语法树:

对于复合表达式,如1 + 2 * 35 - 2 + 3,编译器使用运算符<dfn style="box-sizing: border-box;">优先级</dfn>和<dfn style="box-sizing: border-box;">关联性的</dfn>规则 将表达式解析为单个值。

运算符优先级规则与您在小学中学习的规则 类似,决定了评估不同类型运算符的顺序。在这种情况下,乘法的优先级高于加法,因此2 * 3首先求值。

1 + (2 * 3)
左操作数 操作者 右操作数

关联性确定解析具有相同优先级的运算符的顺序。如果运算符是左关联的,则首先计算左侧的操作数:( (5 - 2) + 3); 如果是右关联的,那么首先评估右侧算子:5 - (2 + 3)

算术运算符是左关联的,因此5 - 2 + 3求值为6

(5 - 2) + 3
左操作数 操作者 右操作数

Swift运算符

Swift标准库包括程序员可能期望来自C系列中另一种语言的大多数运算符,以及一些方便的添加,如nil-coalescing operator(??)和模式匹配operator(~=),以及运算符类型检查(is),型铸造(asas?as!)以及形成开放或封闭范围(.....<)。

中缀运营商

Swift 对二元运算符使用中 表示法(而不是反向波兰表示法)。中缀运算符根据其关联性和优先级按以下顺序分组如下:

BitwiseShiftPrecedence

<< 按位左移
>> 按位右移

MultiplicationPrecedence

* / 划分 剩余
&* 乘以,忽略溢出 &/ 划分,忽略溢出 &% 剩余,忽略溢出
按位AND

AdditionPrecedence

+ - 减去 &+ 添加溢出
& - 减去溢出 按位OR ^ 按位异或

RangeFormationPrecedence

.. < 半开放范围 ... 封闭的范围

CastingPrecedence

键入检查 输入

NilCoalescingPrecedence

?? 没有合并

ComparisonPrecedence

< 少于 <= 小于等于
> 比...更棒 > = 大于或等于
== 等于 != 不相等
=== 相同 !== 不一样
〜= 模式匹配

LogicalConjunctionPrecedence

&& 逻辑和

LogicalDisjunctionPrecedence

逻辑或

DefaultPrecedence

AssignmentPrecedence

= 分配 * = 乘以并分配 / = 划分并分配
%= 剩余并分配 + = 添加并分配 - = 减去并分配
<< = 左移位和分配 >> = 右移位和分配 &= 按位AND和赋值
^ = 按位异或并分配 按位OR和赋值 && = 逻辑AND和分配
逻辑OR和赋值

运算符优先级组最初使用数字优先级定义。例如,乘法运算符定义的优先级值为150,因此它们在加法运算符之前进行求值,这些运算符定义了优先级值140。

在Swift 3中,运算符更改为通过部分排序来定义优先级以形成DAG 或有向非循环图。有关此更改的详细信息,请阅读Swift Evolution提议 SE-0077改进的操作员声明。

一元运算符

除了采用两个操作数的二元运算符之外,还有一元运算符,它采用单个操作数。

前缀运算符

前缀运算符在它们运行的​​表达式之前出现。Swift默认定义了一些:

例如,!前缀运算符否定其操作数的逻辑值,-前缀运算符否定其操作数的数值。

!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 Doublevalues 数组以执行成员添加,它将覆盖先前的连接行为:

// 👿
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不是12Javascript除外)。这真的很直观吗?...或只是熟悉

在决定是否使现有运算符超载时要记住一些事项。

相比之下,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

定制操作员很难打字,因此难以使用,所以要用异国情调的符号来克制。代码应该键入,而不是复制粘贴。

在您自己的代码中覆盖或定义新运算符时,请确保遵循以下准则:

  1. 除非其含义明显且无可争议,否则不要创建运算符。寻找任何潜在的冲突以确保语义一致性。
  2. 注意自定义运算符的优先级和关联性,并且只在必要时定义新的运算符组。
  3. 如果有意义,请考虑为自定义运算符实现赋值变量(例如+=for +

扫码进交流群 有技术的来闲聊 没技术的来学习

691040931

原文转载地址:https://nshipster.com/swift-operators/

上一篇 下一篇

猜你喜欢

热点阅读