Swift運算符

沒有運營商的計劃會是什麼?類,命名空間,條件,循環和命名空間的混合表示什麼都沒有。git

運營商是一個程序的工做。它們是可執行文件的執行; 每一個過程的目的論驅動因素。程序員

小編這裏推薦一個羣:691040931 裏面有大量的書籍和麪試資料哦有技術的來閒聊 沒技術的來學習

運算符優先級和關聯性

若是咱們要剖析一個表達式 - 好比說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求值爲6bash

(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默認定義了一些:

  • +:一元加
  • -:一元減去
  • !:邏輯不
  • ~:按位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 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不是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

定製操做員很難打字,所以難以使用,因此要用異國情調的符號來剋制。代碼應該鍵入,而不是複製粘貼。

在您本身的代碼中覆蓋或定義新運算符時,請確保遵循如下準則:

  1. 除非其含義明顯且無可爭議,不然不要建立運算符。尋找任何潛在的衝突以確保語義一致性。
  2. 注意自定義運算符的優先級和關聯性,而且只在必要時定義新的運算符組。
  3. 若是有意義,請考慮爲自定義運算符實現賦值變量(例如+=for +

掃碼進交流羣 有技術的來閒聊 沒技術的來學習

691040931

原文轉載地址:nshipster.com/swift-opera…

相關文章
相關標籤/搜索