Swift之&&,||,??实现原理

CorHaggerty 5年前
   <h2>Swift之&&,||,??实现</h2>    <h2>operator</h2>    <p>首先需要讲解swift中运算符是以函数的形式存在的,其中包含3种:</p>    <h3>位置</h3>    <ol>     <li>prefix 前置运算符</li>     <li>infix 中间运算符</li>     <li>postfix 后置运算符</li>    </ol>    <h3>配置</h3>    <ol>     <li>associativity 结合性 (包含 left,right和none)</li>     <li>precedence 优先级 (0-255)</li>    </ol>    <h2>&&</h2>    <h3>定义</h3>    <p>我们可以看出结合性为左,优先级120,其次该函数有两个声明,在上一篇文章中提到 <a href="/misc/goto?guid=4959673681750739080" rel="nofollow,noindex">关于@autoclosure的作用</a></p>    <pre>  <code class="language-swift">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  </code></pre>    <h3>实现</h3>    <p>我们可以探索其中的源码,关于对其中 @inline 以及 @——transparent 感兴趣的朋友,可以在swift的docs中查看: <a href="/misc/goto?guid=4959673769784636791" rel="nofollow,noindex">TransparentAttr.tst</a></p>    <pre>  <code class="language-swift">@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>    <h3>分析</h3>    <p>这里面让我开始非常疑惑的两个点:</p>    <ol>     <li>为什么需要定义两个函数</li>     <li>为什么需要throws</li>    </ol>    <p>以下均使用playground演示,首先我们来模拟系统的自定义一个运算符</p>    <pre>  <code class="language-swift">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>    <p>从上可以看出:</p>    <ol>     <li>&&& 左右返回值都为 Bool 类型的时候会调用第一个函数,即上面看到的 <T : BooleanType></li>     <li>&&& 右边为自定义类型的使用会调用调用第二个函数,即上面看到的 <T : BooleanType, U : BooleanType></li>    </ol>    <p>那么接下来解决第二个问题,为什么会 throws 呢?也就是说上述两个函数,如果你把 throws 和 rethrows 都去掉,其余 &&& 照常可以执行,那为什么会加入这两个关键字呢?</p>    <p>首先介绍下两个关键字:</p>    <p>rethrows 和  throws 它们都是标记了一个方法应该抛出错误。但是  rethrows 一般用在参数中含有可以  throws 的方法的高阶函数中</p>    <p>那么我们来继续为 struct Fraction 添加一些处理,分母不能为0,那这种情况我们可以抛出异常来处理,重新定义之后,如下</p>    <pre>  <code class="language-swift">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  }  </code></pre>    <p>这样以来我们就能捕获到第二个闭包可能抛出的异常处理,会让我们所写的函数更加安全</p>    <p>那么同样大家可以试着去分析 ?? 以及 || ,我在这里就不累赘的介绍了</p>    <h2>参考</h2>    <p><a href="/misc/goto?guid=4959673769865429776" rel="nofollow,noindex">错误和异常处理</a></p>    <p><a href="/misc/goto?guid=4959673769950444873" rel="nofollow,noindex">swift源码Boolean</a></p>    <h2>感谢</h2>    <p>梁杰_numbbbbb</p>    <p> </p>    <p>来自: <a href="/misc/goto?guid=4959673770026419869" rel="nofollow">http://archerzz.com/swift/operator.html</a></p>    <p> </p>