目录


1. guard 关键字介绍

在Swift里,有三种类型的语句:简单语句,编译控制语句和控制流语句。简单语句用于构造表达式和声明,编译控制语句用于更改编译器的行为,控制流语句用于控制程序的执行顺序。控制流语句又包含了:循环语句(for, for in, while, repeat while),分支语句(switch, if, guard)和控制转移语句(break, continue, fallthrough, return, throw, defer等)。在分支语句里, if表示条件通过则执行,而guard 结合else表示条件通不过则执行。同样的逻辑,后者可以大大提高代码的可读性。swift官方文档对于guard的定义如下:

A guard statement is used to transfer program control out of a scope if one or more conditions aren’t met.

一个guard 的语句有如下格式:

1
2
3
guard condition else{
    statements
}

2. guard 的应用场景

我们来看看guard的几个应用场景,以下面歌曲Song类举例:

1
2
3
4
5
class Song {
    var name:String?
    var singer: String?
    var age: Double?
}

该Song类有三个可选值实例属性,分别是name, singer, age, 默认值均为nil。我们有一个打印其信息的函数

1
2
3
4
5
6
7
func printInfo0(){
    if let tempName = self.name {
        print("name: \(tempName)")
        return
    }
    print("name is nil")
}

printInfo0()中,我们用Optional Binding先判断self.name是否有值,若有,则打印;否则,打印nil。我们将主要业务逻辑包裹在判断语句中。下面我们用guard来实现相同的逻辑。

1
2
3
4
5
6
7
func printInfo1(){
    guard let tempName = self.name else{
        print("name is nill")
        return
    }
    print("name: \(tempName)")
}

printInfo1()中,我们同样用Optional Binding判断self.name是否有值, 将其没有的情况else先处理。然后在下面处理我们的主要业务逻辑 print("name: \(tempName)"), 这时候的tempName已经拆包,可以直接用,与if let 中的tempName类似。guard在这里就像一个卫士一样,将我们不要的情况先处理,然后在余下函数主体中处理主要业务逻辑。代码可读性的提高,在这个例子中不明显,我们再来看下面这个例子体会一下。

2.1 guard 应用场景:多条件分别判断

同样是上面的Song类,我们改写其printInfo0()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func printInfo0(){
    if let tempName = self.name {
        print("name: \(tempName)")

        if let tempSinger = self.singer{
            print("singer: \(tempSinger)")

            if let tempAge = self.age{
                print("age: \(tempAge)")
                return
            }
            print("age is nil")

            return
        }
        print("singer is nil")
        return
    }
    print("name is nil")
}

同样的逻辑,我们判断三次,如果歌曲有名字,则打印;如果有歌手,则打印;如果有年龄,则打印。否则返回。是不是读起来not feel the right, there must be a better way to do it。 下面我们用guard改写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func printInfo1(){
    guard let tempName = self.name else{
        print("name is nill")
        return
    }
    print("name: \(tempName)")

    guard let tempSinger = self.singer else{
        print("singer is nil")
        return
    }
    print("singer: \(tempSinger)")

    guard let tempAge = self.age else{
        print("age is nil")
        return
    }
    print("age: \(tempAge)")
}

先处理没有名字的情况,然后处理有名字;接着再处理没有歌手的情况,然后处理有歌手; 接着是年龄,也一样。是不是感觉读起来顺畅多了。

2.2 guard 应用场景:多条件同时判断

或者有时候你不需要对每个条件的失败情况进行处理,你需要的是统一处理失败情况,统一处理业务逻辑。例如用if let 改写 printInfo0()

1
2
3
4
5
6
7
8
9
10
11
func printInfo0(){
    if let tempName = self.name,
       let tempSinger = self.singer,
       let tempAge = self.age{
       print("name: \(tempName)")
       print("singer: \(tempSinger)")
       print("age: \(tempAge)")
       return
    }
    print("information is not complete")
}

name, singer, age 都有值时,打印。否则打印”information is not complete”。用guard实现 printInfo1() 如下:

1
2
3
4
5
6
7
8
9
10
11
func printInfo1(){
    guard let tempName = self.name,
          let tempSinger = self.singer,
          let tempAge = self.age else{
        print("information is not complete")
        return
    }
    print("name: \(tempName)")
    print("singer: \(tempSinger)")
    print("age: \(tempAge)")
}

这样将不符合条件的先处理,然后再处理符合条件的主要业务逻辑,代码更清晰易读。

2.3 guard 应用场景:for 循环

guard else 还有一点需要注意的是必须要转移控制,用breakcontinue, 或者return。比如 我们想打印[1, nil, 3, 4, 5]中每一个元素,nil 打印为 nil

1
2
3
4
5
6
7
8
9
10
let possibleNumbers: [Int?] = [1,nil,3,4,5]

for number in possibleNumbers{
    guard let n = number else{
        print("nil")
        break
    }
    print(n)
}
//输出: 1, nil

这里用break打印 “1, nil”不是我们想要的结果,应该用continue,如下

1
2
3
4
5
6
7
8
9
10
let possibleNumbers: [Int?] = [1,nil,3,4,5]

for number in possibleNumbers{
    guard let n = number else{
        print("nil")
        continue
    }
    print(n)
}
//输出: 1, nil, 3, 4, 5

因此在用guard时,应该合理选择 breakcontinue, 或者return

3 总结

guard关键字对于if 相当于一个补集,先处理不需要的情况,再集中精力处理主要业务逻辑,对于提高代码的可读性和修改性起到不小作用。以上三个应用场景归纳起来都是对于guard else的这个特性的应用。在内存管理时的weak-strong dance 里我们也可以用guard先处理nil的情况,这里就不再举例了。希望读者以后可以熟练运用guard关键字。


Share Post

Twitter Google+

Shunmian

The only programmers in a position to see all the differences in power between the various languages are those who understand the most powerful one.