Swift 点滴 - guard 和 if 不应该放在一起讨论

嘿嘿~我有一些小经验打算与你分享~

[Playground 地址](../../assets/source/guard & if.playground.zip)

虽然二者都是处理分支的语法,但 guard 是提前退出,是做一个保证,保证后面的每一句都满足某一条件; 而 if 是假如就如何如何,二者基本不在一个画风。

记住:guard 只适合用来做提前退出,保证后面代码可以正常执行。

我们在 Playground 中敲入以下代码,MyClass2服从MyProtocol.

protocol MyProtocol {
    var protocolFoo: String{get set}
}

class MyClass1 {
    var protocolFoo: String = "protocolBar"

    var classFoo: String = "classFoo"
}

class MyClass2: MyProtocol {
    var protocolFoo: String = "protocolBar"

    var classFoo: String = "classFoo"
}

let myClass1 = MyClass1()

let myClass2 = MyClass2()

接下来就是见证坑爹的时候了:

myClass2.protocolFoo = "2_protocolBar"
guard let myClass2 = myClass2 as? MyProtocol else {
    fatalError("")
}
print(myClass2.protocolFoo)
myClass2.protocolFoo = "2_2_protocolBar"

最后一句一定是编译不过去的。因为你用了 guard ,myClass2 就变成了 MyProtocol ,同时编译器竟然把引用类型(class)认为是值类型,自然也就不能再修改protocolFoo了。仔细想一下感觉蛮坑的。同时你也没有办法使用myClass2.classFoo,自从用了 guard ,连本身是 MyClass2 的信息都弄丢了。 千万别被我之前翻译的那篇为什么 guard 比 if 好 (opens new window)误导,这篇文章仅仅是在处理嵌套或者为了保证后面的代码都满足某些条件时讨论的,并不是说什么时候都应该用 guard 。

最后还是讨论要回到什么时候用 guard ,什么时候用 if 的,我有一个很简单的判别方法:

就用上面的例子来说,如果后面的代码只需要满足服从 MyProtocol 协议的条件,那么就用 guard 吧;但如果只是临时使用一下(必须服从 MyProtocol 的应该打印一下protocolFoo),后面的代码主要还是使用MyClass2

使用 if 的情况:

if let myClass2 = myClass2 as? MyProtocol {
    print(myClass2.protocolFoo)
}
myClass2.classFoo = "2_classFoo"

再重复一遍,如果临时需要某些特性,使用 if ,如果是为了保证后面的代码都满足某些特性,使用 guard。