Swift之&&,||,??實現原理

CorHaggerty 8年前發布 | 11K 次閱讀 Swift Apple Swift開發

Swift之&&,||,??實現

operator

首先需要講解swift中運算符是以函數的形式存在的,其中包含3種:

位置

  1. prefix 前置運算符
  2. infix 中間運算符
  3. postfix 后置運算符

配置

  1. associativity 結合性 (包含 left,right和none)
  2. 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>

分析

這里面讓我開始非常疑惑的兩個點:

  1. 為什么需要定義兩個函數
  2. 為什么需要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>

從上可以看出:

  1. &&& 左右返回值都為 Bool 類型的時候會調用第一個函數,即上面看到的 <T : BooleanType>
  2. &&& 右邊為自定義類型的使用會調用調用第二個函數,即上面看到的 <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
}

這樣以來我們就能捕獲到第二個閉包可能拋出的異常處理,會讓我們所寫的函數更加安全

那么同樣大家可以試著去分析 ?? 以及 || ,我在這里就不累贅的介紹了

參考

錯誤和異常處理

swift源碼Boolean

感謝

梁杰_numbbbbb

 

來自: http://archerzz.com/swift/operator.html

 

 本文由用戶 CorHaggerty 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!