Swift 2引入了guard关键字,它可以用来确保各种数据配置就绪。我在这个网站上看到的一个例子演示了一个submitTapped函数:

func submitTapped() {
    guard username.text.characters.count > 0 else {
        return
    }

    print("All good")
}

我想知道使用guard与使用if条件的老式方法是否有任何不同。它是否提供了简单支票无法获得的好处?


当前回答

与if不同,guard创建的变量可以从其块外访问。打开大量的可选项是有用的。

其他回答

阅读这篇文章,我注意到使用Guard的巨大好处

下面你可以用一个例子来比较guard的用法:

这是没有防备的部分:

func fooBinding(x: Int?) {
    if let x = x where x > 0 {
        // Do stuff with x
        x.description
    }

    // Value requirements not met, do something
}

在这里,您将所需的代码放在所有条件中 您可能不会立即发现这有什么问题,但是您可以想象,如果它嵌套了许多在运行语句之前都需要满足的条件,那么它会变得多么令人困惑

解决这个问题的方法是首先进行每一项检查,如果有任何不符合就退出。这样可以很容易地理解什么条件将使该函数退出。

但是现在我们可以使用guard,我们可以看到它可以解决一些问题:

func fooGuard(x: Int?) {
    guard let x = x where x > 0 else {
        // Value requirements not met, do something
        return
    }

    // Do stuff with x
    x.description
}

检查你想要的条件,而不是你不想要的条件。这同样类似于断言。如果条件不满足, 运行Guard的else语句,跳出函数。 如果条件通过,这里的可选变量将自动在保护的范围内为您展开 语句被调用——在本例中是fooGuard(_:)函数。 您可以尽早检查坏的情况,使您的函数更易于阅读和维护

同样的模式也适用于非可选值:

func fooNonOptionalGood(x: Int) {
    guard x > 0 else {
        // Value requirements not met, do something
        return
    }

    // Do stuff with x
}

func fooNonOptionalBad(x: Int) {
    if x <= 0 {
        // Value requirements not met, do something
        return
    }

    // Do stuff with x
}

如果你还有任何问题,你可以阅读整篇文章:Swift guard声明。

结束

最后,通过阅读和测试,我发现如果你使用guard来打开任何可选选项,

这些未包装的值将保留在您的其余部分中使用 代码块

.

guard let unwrappedName = userName else {
    return
}

print("Your username is \(unwrappedName)")

在这里,打开的值只在if块中可用

if let unwrappedName = userName {
    print("Your username is \(unwrappedName)")
} else {
    return
}

// this won't work – unwrappedName doesn't exist here!
print("Your username is \(unwrappedName)")

警卫的陈述就要做了。这是两个不同的问题

1)它允许我减少嵌套的if语句 2)它是增加我的范围,我的变量可访问

if语句

func doTatal(num1 : Int?, num2: Int?) {
  // nested if statement
    if let fistNum = num1 where num1 > 0 {
        if let lastNum = num2 where num2 < 50 {

          let total = fistNum + lastNum
        }
    }
 // don't allow me to access out of the scope 
 //total = fistNum + lastNum 
}

保安声明

func doTatal(num1 : Int?, num2: Int?) {
   //reduce  nested if statement and check positive way not negative way 
    guard let fistNum = num1 where num1 > 0 else{
      return
    }
    guard  let lastNum = num2 where num2 < 50 else {
     return
    }
    // increase my scope which my variable accessible
    let total = fistNum + lastNum

}

来源:《Swift》中的Guard

让我们看一个例子来清楚地理解它

示例1:

func validate() {         
    guard 3>2 else {             
    print ("False")             
    return         
    }         
    print ("True") //True     
} 
validate()

在上面的例子中,我们看到3大于2,守卫else子句中的语句被跳过并打印True。

示例2:

func validate() {         
    guard 1>2 else {             
    print ("False")            //False 
    return         
    }         
    print ("True")      
} 
validate()

在上面的例子中,我们看到1小于2,守卫else子句内的语句被执行,False被打印出来,后面跟着return。

Example 3: gaurd let, unwrapping optionals through guard let

func getName(args myName: String?) {
     guard let name = myName, !name.isEmpty else {
     print ("Condition is false")          // Condition is false            return         
     }         
     print("Condition is met\(name)")     
} 
getName(args: "")

在上面的例子中,我们使用保护let来打开可选项。在函数getName中,我们定义了一个可选的字符串类型变量myName。然后使用守卫let检查变量myName是否为nil,如果没有赋值给name,再次检查,name不为空。如果两个条件都是合格的,即true, else块将被跳过并打印“条件符合名称”。

基本上,我们在这里检查两个用逗号分隔的东西,首先是展开和可选,然后检查它是否满足条件。

这里我们没有向函数传递任何东西,即空字符串,因此打印Condition为false。

func getName(args myName: String?) {
     guard let name = myName, !name.isEmpty else {
     print ("Condition is false")          
     return         
     }        
     print("Condition is met \(name)") // Condition is met Hello    
} getName(args: "Hello")

在这里,我们将“Hello”传递给函数,您可以看到输出打印为“Condition is met Hello”。

这确实有两大好处需要保护。一个是避免厄运金字塔,就像其他人提到的那样——许多恼人的if语句嵌套在彼此之间,越来越向右移动。

另一个好处是你想要实现的逻辑通常是“if not let”而不是“if let {} else”。

这里有一个例子:假设你想要实现accumulate -一个map和reduce之间的交叉,它会返回一个运行的reduce数组。下面是guard:

extension Sliceable where SubSlice.Generator.Element == Generator.Element {

    func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {
        // if there are no elements, I just want to bail out and
        // return an empty array
        guard var running = self.first else { return [] }

        // running will now be an unwrapped non-optional
        var result = [running]

        // dropFirst is safe because the collection
        // must have at least one element at this point
        for x in dropFirst(self) {
            running = combine(running, x)
            result.append(running)
        }
        return result
    }

}


let a = [1,2,3].accumulate(+)  // [1,3,6]
let b = [Int]().accumulate(+)  // []

你怎么写它没有守卫,但仍然使用第一,返回一个可选?就像这样:

extension Sliceable where SubSlice.Generator.Element == Generator.Element {

    func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {

        if var running = self.first  {
            var result = [running]

            for x in dropFirst(self) {
                running = combine(running, x)
                result.append(running)
            }
            return result
        }
        else {
            return []
        }
    }

}

额外的嵌套是恼人的,而且,if和else相隔太远也不符合逻辑。让空case提前退出,然后继续函数的其余部分,就好像这是不可能的一样,可读性要高得多。

用保护我们的意图是明确的。如果这个特定条件不满足,我们就不想执行其余的代码。 在这里我们也可以扩展链,请看看下面的代码:

guard let value1 = number1, let value2 = number2 else { return }
 // do stuff here