Swift之&&,||,??實現原理
Swift之&&,||,??實現
operator
首先需要講解swift中運算符是以函數的形式存在的,其中包含3種:
位置
- prefix 前置運算符
- infix 中間運算符
- postfix 后置運算符
配置
- associativity 結合性 (包含 left,right和none)
- precedence 優先級 (0-255)
&&
定義
我們可以看出結合性為左,優先級120,其次該函數有兩個聲明,在上一篇文章中提到 關于@autoclosure的作用
infix operator && {
associativity left
precedence 120
}
public func &&<T : BooleanType>(lhs: T, @autoclosure rhs: () throws -> Bool) rethrows -> Bool
public func &&<T : BooleanType, U : BooleanType>(lhs: T, @autoclosure rhs: () throws -> U) rethrows -> Bool
實現
我們可以探索其中的源碼,關于對其中 @inline 以及 @——transparent 感興趣的朋友,可以在swift的docs中查看: TransparentAttr.tst
@inline(__always)
public func && <T : Boolean, U : Boolean>(
lhs: T, rhs: @autoclosure () throws -> U
) rethrows -> Bool {
return lhs.boolValue ? try rhs().boolValue : false
}
@_transparent
public func && <T : Boolean>(
lhs: T, rhs: @autoclosure () throws -> Bool
) rethrows -> Bool {
return lhs.boolValue ? try rhs().boolValue : false
}
</code></pre>
分析
這里面讓我開始非常疑惑的兩個點:
- 為什么需要定義兩個函數
- 為什么需要throws
以下均使用playground演示,首先我們來模擬系統的自定義一個運算符
infix operator &&& {
associativity left
precedence 120
}
func &&& <T : BooleanType>(
lhs: T, @autoclosure rhs: () throws -> Bool
) rethrows -> Bool {
"test1"
return lhs.boolValue ? try rhs().boolValue : false
}
func &&& <T : BooleanType, U : BooleanType>(
lhs: T, @autoclosure rhs: () throws -> U
) rethrows -> Bool {
"test2"
return lhs.boolValue ? try rhs().boolValue : false
}
struct Fraction {
let numerator: Double // 分子
let denominator: Double // 分母
init(numerator: Double, denominator: Double) {
self.numerator = numerator
self.denominator = denominator
}
}
// 使其能夠使用獲取Bool值
extension Fraction: BooleanType {
var boolValue: Bool {
// 不等于0即為真
return numerator / denominator != 0
}
}
// 測試
let username = "admin"
let password = "123456"
let success = username.characters.count > 0 &&& password.characters.count > 0 // true 并且輸出test1
success &&& Fraction(numerator: 100, denominator: 50) // true 并且輸出test2
</code></pre>
從上可以看出:
- &&& 左右返回值都為 Bool 類型的時候會調用第一個函數,即上面看到的 <T : BooleanType>
- &&& 右邊為自定義類型的使用會調用調用第二個函數,即上面看到的 <T : BooleanType, U : BooleanType>
那么接下來解決第二個問題,為什么會 throws 呢?也就是說上述兩個函數,如果你把 throws 和 rethrows 都去掉,其余 &&& 照常可以執行,那為什么會加入這兩個關鍵字呢?
首先介紹下兩個關鍵字:
rethrows 和 throws 它們都是標記了一個方法應該拋出錯誤。但是 rethrows 一般用在參數中含有可以 throws 的方法的高階函數中
那么我們來繼續為 struct Fraction 添加一些處理,分母不能為0,那這種情況我們可以拋出異常來處理,重新定義之后,如下
struct Fraction {
// 添加錯誤類型
enum Error: ErrorType {
case DenominatorZero
}
let numerator: Double // 分子
let denominator: Double // 分母
init(numerator: Double, denominator: Double) throws {
// 保證分母不能為0
guard denominator != 0 else {
throw Error.DenominatorZero
}
self.numerator = numerator
self.denominator = denominator
}
}
// 使其能夠使用獲取Bool值
extension Fraction: BooleanType {
var boolValue: Bool {
// 不等于0即為真
return numerator / denominator > 0
}
}
// 重新測試
let username = "admin"
let password = "123456"
let success = username.characters.count > 0 &&& password.characters.count > 0 // true 并且輸出test1
// 需要添加異常處理
do {
try success &&& Fraction(numerator: 100, denominator: 50) // true 并且輸出test2
try success &&& Fraction(numerator: 100, denominator: 0) // 輸出error
} catch let error {
error
}
這樣以來我們就能捕獲到第二個閉包可能拋出的異常處理,會讓我們所寫的函數更加安全
那么同樣大家可以試著去分析 ?? 以及 || ,我在這里就不累贅的介紹了
參考
感謝
梁杰_numbbbbb
來自: http://archerzz.com/swift/operator.html