在关系数据库的领域语言中, SQL已然变成了近乎唯一的标准, 而观察SQL语句, 它最大的特色(或者说便利), 其实就是where子语句的运用. Swift语言作为一个新语言, 自然而然的吸取了SQL这种领域语言的特色, 也就是where子语句.
由于Swift语言已经有if语句, 为何还要加入where语句, 我认为是编译解析的方便, 本来Swift语言去掉了if后的条件括号, 已经增加了if语句的解析成本, 还要加上if语句作为子语句存在, 那更加是成本巨大了. 现在的设定下, if作为标准判断语句, 而where是作为判断的子语句, 应该还是清晰的. 但是, where语句应用的地方有很多, 这里我具体罗列一下, 方便大家参考.
1. 作为case的子语句, 在swift ... case中, case 之后, 再加上一个where子语句作为判断条件.
比如:
let box = (200, 200)
switch box {
case (let w, let h) where w == h :
print("well done")
default:
print("do nothing")
}
在这里, where语句其实就是一个简单的if语句, 是针对case的结果进行再度判断.
特别要注意, 在Swift3之前, case语句是可以独立存在, 当然, 其后也能接where语句. 但是, 个人认为这是一个非常愚蠢的设计, 所幸, 苹果去掉了独立case语句的设计.
2. 作为泛型的类型预判断.
比如:
class A <T> where T : UIViewController {
func show(t:T) {
print("test")
}
}
这里的<T> where T: UIViewController 其实也可以缩写成<T:UIViewController>
值得注意的是, 这里是不能写成T == UIViewController的, 在swift语言中, 有一个强制的规范, 那就是泛型类型, 只能跟另外一个泛型类型进行等号对比, 冒号, 则只能用在Protocol的判断上. 很多初学者, 看到泛型的where子语句中, 又有冒号, 又有等号, 很可能会有此混乱.
注意, where子语句, 并不是接着类名称的, 而是放在类名称的最后一部分, Swift在编译的时候, 会跳到最后部分进行解析, 对应之前的泛型模板.
如: class A 还有一个父类, 那么, 就要写成class A <T> : B where T : UIViewController, 这个where一定是在最后的位置. 同样的, 函数的泛型预判断, 也能使用where子语句, 也是采用一样的规则.
3. 作为catch的判断子语句.
例子如下:
enum MyError: Error {
case whatFuckError(errorNo:Int)
}
func aa() throws {
throw MyError.whatFuckError(errorNo: 1)
}
// 前面是伪造的一次throw. 别理他
do {
try aa()
} catch MyError.whatFuckError(let e) where e == 1 {
print("catch this")
}
这里可以看得出来, 其实, 在Swift语言中, catch就是一个变种的switch语句, 所以, 下面的catch语句, 就是一个特异的case语句, 既然where能够作为子语句存在于case语句中, 自然的, 也能作为子语句存在于catch之中.
上述三种方式, 是比较常用的where子语句使用场景. 在Swift3.0之前, 其实if语句也能使用where子语句, 后来, 大概是苹果自己都觉得这样做有点画蛇添足, 就去掉了, 现在使用逗号来达到类似效果.