【发布时间】:2017-12-16 06:04:08
【问题描述】:
在我最近接触 Python 之后,我学会了欣赏其 conditional expressions 的可读性,其形式为 X if C else Y。
当经典的ternary conditional operator ?: 将条件作为第一个参数时,感觉就像赋值完全是关于选择的。当您尝试嵌套多个三元运算符时,它会变得很难看……当条件在第一个表达式之后移动时,感觉更像是函数的数学定义。我发现这有时有助于代码清晰。
作为code kata,我想在Swift 中实现python 风格的条件表达式。似乎唯一能让我获得所需语法的工具是自定义运算符。它们必须由符号组成。 Math symbols in Unicode 将逻辑中的 double turnstile 符号标记为 TRUE ⊨ 并且划掉的版本不是 TRUE ⊭……所以我选择了 @987654330 @ 和 |!=。到目前为止,在为找到正确的优先级而奋斗了一段时间之后,我有这个:
// Python-like conditional expression
struct CondExpr<T> {
let cond: Bool
let expr: () -> T
}
infix operator ==| : TernaryPrecedence // if/where
infix operator |!= : TernaryPrecedence // else
func ==|<T> (lhs: @autoclosure () -> T, rhs: CondExpr<T>) -> T {
return rhs.cond ? lhs() : rhs.expr()
}
func |!=<T> (lhs: Bool, rhs: @escaping @autoclosure () -> T) -> CondExpr<T> {
return CondExpr<T>(cond: lhs, expr: rhs)
}
我知道结果看起来不是很 swifty 或特别可读,但从好的方面来说,即使表达式分布在多行上,这些运算符也可以工作。
let e = // is 12 (5 + 7)
1 + 3 ==| false |!=
5 + 7 ==| true |!=
19 + 23
当你用空白来创造创意时,它甚至感觉有点pythonic ???? :
let included =
Set(filters) ==| !filters.isEmpty |!=
Set(precommitTests.keys) ==| onlyPrecommit |!=
Set(allTests.map { $0.key })
我不喜欢第二个自动关闭必须逃脱。 Nate Cook's answer about custom ternary operators in Swift 2 使用了 Swift 3 中不再存在的柯里化语法……我猜这在技术上也是一个转义闭包。
有没有办法在不逃避关闭的情况下完成这项工作? 这还重要吗?也许 Swift 编译器足够聪明,可以在编译时解决这个问题,从而不会影响运行时?
【问题讨论】:
标签: swift