Swift中 Nil Coalescing 運算子的使用技巧
在Swift官方《The Swift Programming Language》文件 Beta 5 版本中的 Basic Operators 一節中新增了Nil Coalescing Operator小結,介紹了一個新的運算子Nil Coalescing,符號是 ?? ,它的表現形成如下:
let c = a ?? b
這個運算子有兩個條件:
a. 必須是Optional型別的。
b. 的型別必須要和a解包後的值型別一致。
符合這兩個條件後,我們來解釋一下上述這行程式碼,意思就 是c 的值是 a 或 b 中一個的值,但有前提條件,就是當 a 解包後值不為 nil 時,那麼就將 a 解包後的值賦值給 c,如果 a 解包後值為 nil,那麼就將 b 的值賦值給c。
我們還可以用三目運算來更形象的解釋這個運算子:
let c = a != nil ? a! : b
從上面的程式碼我們很容易理解,當a的值不等於nil時,將a解包後的值賦值給c,否則將b的值賦值給c。
我們來看看官方給的程式碼示例:
let defaultColorName = "red" var userDefinedColorName: String? // 預設值為nil var colorNameToUse = userDefinedColorName ?? defaultColorName // 因為userDefinedColorName的值是nil,所以colorNameToUse的值為"red"
userDefinedColorName = "green" colorNameToUse = userDefinedColorName ?? defaultColorName // 因為userDefinedColorName的值不為nil,所以colorNameToUse的值為"green"
大家看到這應該對 Nil Coalescing 這個運算子有比較清晰的理解了,但在實際運用中,我們還需要注意以下幾點。
編譯器中的型別匹配原則
原諒我在末尾加的 ; ,編碼習慣而已 = =||
我們先來看一段程式碼:
let a: Int? = nil; let b: Int? = 7; let c = a != nil ? a! : b; // 因為a的預設值為nil,所以c的值為{Some 7} let d = a ?? b; // 這裡d的值為nil,這是怎麼回事?
首先我們需要注意的是,在官方文件中有這麼一句話:“The expression b must match the type that is stored inside a”。但是上面的程式碼示例中,我們的 b 是 Int? 型別,那麼此時我們的編譯器會怎麼處理呢?我們通過自己實現一個 Nil Coalescing 運算子來說明,程式碼片段如下:
infix operator ??? { associativity right; precedence 110; } func ???<T>(a: T?, b: @autoclosure () -> T) -> T { return a != nil ? a! : b(); } let d = a ??? b; // 這裡d的值仍然是nil
從上面的程式碼片段中我們可以看出,a的型別是根據傳入的b的型別決定的,所以當我們傳入的 b 是 Int? 型別時,編譯器其實將 a 的型別自動轉換為 Int?? 型別了,也就是 Optional(a) ,那麼我們就能解釋 let d = a ?? b; 這行程式碼。因為 a == nil 但是 Optional(a) != nil,所以 d = Optional(a)! ,d 的值為 nil 。
Nil Coalescing 運算子返回值的型別
我們先看示例程式碼片段:
let a: Int? = nil; let b: Int? = 5; let c: Int? = 6; // 因為a的預設值為nil,所以將b的值賦值給x,x的值為{Some 5},型別為Int? let x = a != nil ? a! : b; // 因為c的值不為nil,所以將c解包後的值賦值給y,但是y的值卻是{Some 6},而不是6,這是怎麼回事? let y = c != nil ? c! : b;
根據上面我們提到的編譯器中型別判斷的原則就可以理解了,因為b的型別是Int?,所以在編譯時 c 的型別已經成了 Int?? ,所以為 Int?? 解包的型別就是 Int? 了。
如果我們宣告變數 y 的型別,編譯器就要提出抗議了:
// 如何a為Int?型別,那麼編譯器就不會通過,因為會導致賦值運算子兩邊型別不等 let x: Int = a != nil ? a! : b; // 這種寫法和上面一樣,都不會編譯通過 let y: Int = a ?? b;
相關文章
- Swift - 11 - nil聚合運算Swift
- Swift中自定義運算子Swift
- javascript中&&運算子和||運算子的使用JavaScript
- Swift--基本運算子Swift
- Swift 自定義運算子Swift
- Swift 語言的基本運算子Swift
- js 與或運算子&&和||使用技巧JS
- 幾個優雅的JavaScript運算子使用技巧JavaScript
- swift 區間運算子(... 和 ..Swift
- iOS Swift邏輯運算子iOSSwift
- 8.Golang中的運算子-算術運算子、關係運算子、邏輯運算子、賦值運算子Golang賦值
- Swift語言指南(九)--基本運算子Swift
- swift 基礎筆記二(運算子)Swift筆記
- js中的運算子JS
- MySQL中的運算子MySql
- swift高階運算子-讀書筆記Swift筆記
- swift 自定義正規表示式運算子 =~Swift
- # JavaScript中的 || 與 && 運算子JavaScript
- python中的運算子Python
- (3)mysql 中的運算子MySql
- php運算子運用之型別運算子該如何使用PHP型別
- 運算子 運算子
- MySQL的四種運算子(算術運算子、比較運算子、邏輯運算子和位運算子)MySql
- Python 中的特殊運算子Python
- JS 中的邏輯運算子JS
- PHP中的比較運算子PHP
- 【linux】Shell中的運算子Linux
- php型別運算子的使用PHP型別
- 運算子的關係,什麼叫一元運算子,二元運算子,三元運算子,運算子優先順序,以及運算子的
- 重讀 Swift 之二:Operator Declaration(運算子過載)Swift
- php運算子 比較運算子 邏輯運算子 三元運算子PHP
- 算術運算子裡的特殊運算子
- 運算子-賦值運算子賦值
- 位運算子在JS中的妙用JS
- C++中運算子的過載C++
- js中的|與 && 運算子詳解JS
- Python3中的運算子Python
- vue中的三元運算子Vue