【问题标题】:Do Swift Switch short circuit?Swift Switch 会短路吗?
【发布时间】:2017-04-19 08:13:53
【问题描述】:

具有多个评估的 switch 语句是否短路?

可能没关系,但我很好奇。


这是一个简单的例子:

let one = 1
let two = true
let three = false


switch (one, two, three) {
case let (0, b, c) where b==c:
    break

case (0, true, true):
    break

default:
    break
}

在第一个 case 语句中,'where' 评估是否会发生?

在第二种情况下,'two' == true 会发生吗?

【问题讨论】:

    标签: swift switch-statement short-circuiting


    【解决方案1】:

    @J.beenie 的回答很好地(并且令人信服地)处理了您的第一个问题。 b == c 将不会被调用,因为您的初始 one0 不匹配,这是一个经典的 AND 短路。

    您的第二个问题取决于元组的== 的实现。根据a comment to this question,这自 2.2.1 以来一直是 Swift 语言的一部分,标准实现当然会短路,因为它是最快的事情。因此,在您的第二种情况下,不会比较第二个元素。

    顺便说一句:您不需要在 Swift switch 语句中使用 break,如果您愿意,您可以使用 fallthrough

    更正: 事实证明,我的猜测只对了一半。 switch 语句中的模式匹配似乎比我预期的要多。我尝试使用我自己的 Bool 枚举来劫持 ==(大致遵循 this post(并针对 Swift 3 进行调整))并得到了一些令人惊讶的结果:

    import Cocoa
    
    let one = 1
    let two:MyBool = .myTrue
    let three:MyBool = .myFalse
    typealias ThreeTuple = (o:Int, tw:MyBool, th:MyBool)
    let tuple:ThreeTuple
    tuple  = (one, two, three)
    
    switch tuple {
    case let (1, b, c) where b == c:
       print("first case")    
    case (1, .myTrue, .myFalse):
        print("second case")
     default:
        print("default")
    }
    
    enum MyBool : ExpressibleByBooleanLiteral, Equatable  {
        case myTrue, myFalse
        public init() { self = .myFalse }
        public init(booleanLiteral value: BooleanLiteralType) {
            self=value ? .myTrue : .myFalse
        }
    }
    
    func ==(lhs: MyBool, rhs: MyBool) -> Bool {
        print("evaluate ==")
        switch (lhs, rhs) {
        case (.myTrue,.myTrue), (.myFalse,.myFalse):
            return true
        default:
            return false
        }
    }
    

    产生

    evaluate ==
    second case
    

    在这一点上,我感到非常惊讶。 ==MyBool 值的唯一评估源自第一个 case 中的 where b == c 子句,所有元组“比较”都不使用 MyBool == 函数嗯>!!我怀疑优化器有干扰,所以我把 switch 变成了 func

    func match(_ tuple:ThreeTuple) {
        switch tuple {
         case let (1, b, c) where b == c:
            print("first case")
         case (1, .myTrue, .myFalse):
            print("second case")
         default:
            print("default")
        }
    }
    

    这应该排除在编译时过度优化,但是当我现在要求时

    match((1, .myTrue, .myTrue))
    match((1, .myTrue, .myFalse))
    match((0, .myTrue, .myFalse))
    

    我明白了

    evaluate ==
    first case
    evaluate ==
    second case
    default
    

    evaluate == 仍然仅源自第一个 case。因此,唯一合理的结论似乎是在switch 语句中的模式匹配过程中发生了“一些其他的魔法”。如果我能弄清楚那是什么,我试图用谷歌搜索,但到目前为止无济于事。无论如何,似乎方式的短路比我预期的要多。

    【讨论】:

    • 写一些代码来证明第二个case语句也短路是很酷的。虽然不知道怎么做。
    • @J.beenie 你是对的,似乎还有其他事情发生,模式匹配在 Swift 中似乎优化得非常好 (TM)。让我们看看是否有人可以对此有所了解。
    【解决方案2】:

    使用以下代码测试您的问题:

    let one = 1
    let two = true
    let three = false
    
    
    switch (one, two, three) {
    case let (0, b, c) where b - c:
        break
    
    case (0, true, true):
        break
    
    default:
        break
    }
    
    extension Bool{
        static func - (lhs: Bool, rhs: Bool) -> Bool {
            print("foo")
            return lhs == rhs
    
        }
    }
    

    在游乐场

    只需将第一个 0 更改为 1,看看会发生什么。

    答案是肯定的;)它确实短路了。

    【讨论】:

      猜你喜欢
      • 2011-04-03
      • 2011-04-12
      • 2011-03-10
      • 2013-12-18
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      • 2023-01-25
      • 2019-05-07
      相关资源
      最近更新 更多