Swift之&&,||,??实现原理
CorHaggerty
8年前
<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>