Swift开关是否短路?
Do Swift Switch short circuit?
具有多个评估的 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' 评估会发生吗?
在第二个 case 语句中,'two' == true 会发生吗?
使用以下代码测试您的问题:
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,看看会发生什么。
答案是肯定的 ;) 它会短路。
@J.beenie 的回答很好地(并且令人信服地)处理了您的第一个问题。 b == c
将不会被调用,因为您的初始 one
与 0
不匹配,这是经典的 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
子句,所有元组 "comparisons" 不使用 MyBool
==
功能 完全 !!我怀疑优化器在干扰所以我把 switch
变成了 func
as
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
。因此,唯一合理的结论似乎是 "some other magic" 在 switch
语句中的模式匹配期间进行。我试图 google 如果我能弄清楚那是什么,但到目前为止无济于事。无论如何,似乎 短路比我预期的要多。
具有多个评估的 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' 评估会发生吗?
在第二个 case 语句中,'two' == true 会发生吗?
使用以下代码测试您的问题:
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,看看会发生什么。
答案是肯定的 ;) 它会短路。
@J.beenie 的回答很好地(并且令人信服地)处理了您的第一个问题。 b == c
将不会被调用,因为您的初始 one
与 0
不匹配,这是经典的 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
子句,所有元组 "comparisons" 不使用 MyBool
==
功能 完全 !!我怀疑优化器在干扰所以我把 switch
变成了 func
as
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
。因此,唯一合理的结论似乎是 "some other magic" 在 switch
语句中的模式匹配期间进行。我试图 google 如果我能弄清楚那是什么,但到目前为止无济于事。无论如何,似乎 短路比我预期的要多。