Swift 中關于”??”操作符一些有意思的事情
Swift 的語法在保證安全和健壯的基礎上,又帶有很多非常靈活的特性,比如 ?? 操作符就是其中一個。大家可能已經了解它,也可能有些同學不了解它,這里給大家整理了關于這個操作符值得一看的討論。
?? 操作符簡述
在展開討論之前,我們先來了解這個操作符的作用是什么。這個操作符和 Optional 相關,讓我們來看一個例子:
var a:Int? print(a ?? 2) //2
?? 操作符的左邊是一個 Optional 值,右邊是一個普通值,它的作用就是,如果左邊的 Optional 值為 nil, 那么就使用右邊的普通值作為返回值,如果左邊的 Optional 不為 nil,則返回左邊的 Optional 解包后的值。
比如我們這個例子中,變量 a 的值是 nil,所以 print 語句輸出的就是后面的默認值 2。
剛才那個例子,如果不用 ?? 操作符,那么就是這樣的邏輯:
print(a == nil ? 2 : a)
讓我們來看看 ?? 操作符的定義:
func ?? (optional: T?, @autoclosure defaultValue: () throws -> T) -> T
把它簡化一下,就是:
func ?? (optional: T?, defaultValue: () throws -> T) -> T
它會接受一個 T 類型的 Optional 值,和一個 T 類型的普通值作為默認值, 然后返回一個解包后的 T 類型的值。這個最終返回值是要根據第一個參數是否為空來確定。
?? 操作符的一些討論
?? 操作符可以讓我們更方便的處理 Optional。 但它也存在一些小問題,Swift 的官方郵件組中大家就有討論。比如這段代碼:
func test(x: ((String) -> String)? = nil) { let qf = { (p:String) -> String in return "tt" } let fn = x ?? qf fn("tt") }
test 函數它接受另外一個 Optional 類型的參數,然后在它內部用 ?? 操作符判斷傳進來的函數 x 是否為 nil,如果是,則用內部的另外一個函數 qf 來替代它。
初步來看,這樣的代碼應該沒有什么問題,?? 的左邊的變量類型是 ((String) -> String)?, 而右邊的變量類型是 (String) -> String, 符合 ?? 操作符的定義。
但這段對 ?? 操作符的使用在實際編譯的時候報錯了。 我們必須把 qf 也聲明成 Optional 類型,才可以使用:
let qf:((String) -> String)? = { (p:String) -> String in return "tt" } let fn = (x ?? qf)! fn("tt")
這樣雖然編譯通過了,但卻不符合 ?? 操作符的定義了。這次兩邊都是 Optional 類型,而表達式的返回值也是 Optional。
這時關于 ?? 在 Swift 郵件組中最近的一個討論,最后的一次回復說這是 Swift 的一個 bug, 將會在 Swift 3.0 版本中修復,這時這個回復的原文:
?? 操作符兩邊的類型可以不一樣
在郵件組里,還有一個討論,大家可以看一下這段代碼:
var a:Int? print(a ?? "test")
注意哦,左邊的 a 是 Int? 類型的, 而右邊是一個 String 字符串。 這段代碼在目前的 Swift 2.2 編譯上是可以編譯通過的。
這個話題討論的比較多,比較合理的一個解釋是 Swift 編譯器會根據當前表達式所在的場景進行相應的向上轉型。
比如作為 print 函數的參數,編譯器會將它們都看做 Any 類型,因為 print 函數接受的就是 Any 類型的參數。所以這個語句可以編譯通過。
如果這個語句用在這個場景,就會導致編譯失敗了:
let x = a ?? "test"
這次的場景,是將它的返回值賦值給 x。 但這次編譯器就無法確定他們的通用類型,而將他們看做兩個不同的類型,這樣就導致編譯失敗了。
同樣的,這段代碼就可以編譯通過:
let x = a ?? NSDate()
按照剛才的邏輯,那么因為后面的類型是 NSDate 它們都可以是 NSObject 的子類,所以編譯器將它們都作為 NSObject 的通用類型來處理了。
而上面的那個例子 let x = a ?? "test" 因為后面的字符串是 Swift 中的 String 類型,編譯器就無法找到它們的通用父類,就導致失敗了。
當然這是目前的討論和分析結果,大家也可以一起來思考,來講你的分析與大家交流。
總結
這次我們一起討論了 ?? 操作符的作用,以及它在使用中的一些要注意的點。從這幾處中可以看到語言本身的很多細節。Swift 郵件組是一個非常好的資源,里面會有很多關于各個話題的深入討論,而且都是完全開放的,大家也可以到它的主頁申請訪問: https://lists.swift.org/mailman/listinfo/swift-users
轉自: swiftcafe