Ключевое слово Swift guard

В Swift 2 введено ключевое слово guard, которое можно использовать для обеспечения готовности готовых к отправке данных. Пример, который я видел на этом веб-сайте, демонстрирует функцию submitTapped:

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

    print("All good")
}

Мне интересно, если использование guard не отличается от старомодного, используя условие if. Предоставляет ли он преимущества, которые вы не могли получить, используя простую проверку?

Ответ 1

Чтение этой статьи Я заметил большие преимущества, используя Охрана

Здесь вы можете сравнить использование защиты с примером:

Это часть без охраны:

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

    // Value requirements not met, do something
}
  • Здесь вы ставите свой желаемый код во все условия

    Вы не можете сразу увидеть проблему с этим, но вы могли бы представить себе, как это может смутить, если в нем было множество условий, которые все должны были быть выполнены перед выполнением ваших утверждений.

Путь к очистке - сначала выполнить каждую из ваших проверок и выйти, если какой-либо arent встретился. Это позволяет легко понять, какие условия вызывают выход этой функции.

Но теперь мы можем использовать защиту, и мы можем видеть, что можно решить некоторые проблемы:

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
}

Если у вас все еще есть вопросы, вы можете прочитать всю статью: Свифт-охранник.

Обтекание

И, наконец, чтение и тестирование я обнаружил, что если вы используете 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)")

Ответ 2

В отличие от if, guard создает переменную, к которой можно получить доступ из-за пределов ее блока. Полезно развернуть много Optional s.

Ответ 3

Есть два больших преимущества для guard. Один из них избегает пирамиды обреченности, о чем говорили другие, - много раздражающих if let утверждений, вложенных друг в друга, движущихся далее и дальше вправо.

Другим преимуществом часто является логика, которую вы хотите реализовать, больше "if not let", чем "if let { } else".

Вот пример: предположим, что вы хотите реализовать accumulate - крест между map и 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(+)  // []

Как вы могли бы написать его без охраны, но все же используя first, который возвращает необязательный? Что-то вроде этого:

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. Его гораздо более читаемый, чтобы иметь ранний выход для пустого случая, а затем продолжить с остальной функцией, как будто это не было возможным.

Ответ 4

Когда условие выполняется с помощью guard, он предоставляет переменные, объявленные в блоке guard, остальной части кодового блока, внося их в область видимости. Что, как было сказано ранее, наверняка пригодится с вложенными операторами if let.

Обратите внимание, что для защиты требуется return или бросок в инструкции else.

Разбор JSON с защитой

Ниже приведен пример того, как можно разобрать объект JSON с помощью функции guard, а не if-let. Это выдержка из записи в блоге, которая содержит файл детской площадки, который вы можете найти здесь:

Как использовать Guard в Swift 2 для разбора JSON

func parseJSONWithGuard(data : [String : AnyObject]) throws -> Developer {

    guard let firstname = data["First"] as? String  else {
        return Developer() // we could return a nil Developer()
    }

    guard let lastname = data["Last"] as? String else {
        throw ParseError.BadName // or we could throw a custom exception and handle the error
    }

    guard let website = data["WebSite"] as? String else {
        throw ParseError.BadName
    }

    guard let iosDev = data["iosDeveloper"] as? Bool else {
        throw ParseError.BadName
    }



    return Developer(first: firstname, last: lastname, site: website, ios: iosDev)

}

скачать детскую площадку: защитная площадка

Дополнительная информация:

Здесь выдержка из Руководство по языку Swift Programming:

Если выполняется условие охранных операторов, выполнение кода продолжается после закрытия закрывающей скобки. Любые переменные или константы которые были присвоены значениям с использованием необязательной привязки как части для остальной части кодового блока доступно условие, что охранник появляется оператор.

Если это условие не выполняется, код внутри ветки else казнены. Эта ветка должна передать управление для выхода из блока кода что этот защитный оператор появляется. Он может сделать это с помощью элемента управления перевод, например, возврат, перерыв или продолжение, или он может вызвать функция или метод, которые не возвращаются, например fatalError().

Ответ 5

Одним из преимуществ является устранение множества вложенных операторов if let. Смотрите видеоролик WWDC "Что нового в Swift" около 15:30, раздел под названием "Пирамида судьбы".

Ответ 6

С помощью охраны наше намерение становится ясным. мы не хотим выполнять остальную часть кода, если это конкретное условие не выполняется. здесь мы также можем расширить цепочку, пожалуйста, посмотрите ниже код:

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

Ответ 7

Когда использовать охранников

Если у вас есть контроллер представления с несколькими элементами UITextField или каким-либо другим типом пользовательского ввода, вы сразу заметите, что вы должны развернуть необязательный textField.text, чтобы получить доступ к тексту внутри (если есть!). isEmpty здесь не поможет, без ввода текстовое поле просто вернет ноль.

Таким образом, у вас есть несколько из них, которые вы разворачиваете и в конце концов передаете в функцию, которая отправляет их на конечную точку сервера. Мы не хотим, чтобы серверный код имел дело с нулевыми значениями или по ошибке отправлял недопустимые значения на сервер, поэтому сначала следует развернуть эти входные значения с защитой.

func submit() {
    guard let name = nameField.text else {
        show("No name to submit")
        return
    }

    guard let address = addressField.text else {
        show("No address to submit")
        return
    }

    guard let phone = phoneField.text else {
        show("No phone to submit")
        return
    }

    sendToServer(name, address: address, phone: phone)
}

func sendToServer(name: String, address: String, phone: String) {
  ...
}

Вы заметите, что наша коммуникационная функция сервера принимает необязательные значения String в качестве параметров, следовательно, защитное развертывание заранее. Развертывание немного не интуитивно понятно, потому что раньше его разворачивали с помощью if let, который разворачивает значения для использования внутри блока. Здесь у оператора guard есть связанный блок, но на самом деле это блок else - то есть то, что вы делаете в случае неудачного развертывания - значения развертываются прямо в тот же контекст, что и сам оператор.

//разделение интересов

Без охраны

Без использования охраны, мы получаем большую кучу кода, который напоминает пирамиду гибели. Это плохо масштабируется для добавления новых полей в нашу форму или для очень удобочитаемого кода. За отступами может быть трудно следить, особенно с таким количеством других операторов на каждой ветке.

func nonguardSubmit() {
    if let name = nameField.text {
        if let address = addressField.text {
            if let phone = phoneField.text {
                sendToServer(name, address: address, phone: phone)
            } else {
                show("no phone to submit")
            }
        } else {
            show("no address to submit")
        }
    } else {
        show("no name to submit")
    }
}

Да, мы могли бы даже объединить все эти операторы let в один оператор, разделенный запятыми, но мы потеряли бы возможность выяснить, какой оператор потерпел неудачу, и представить сообщение пользователю.

https://thatthinginswift.com/guard-statement-swift/

Ответ 8

Заявление о защите. это несколько разных

1) это позволяет мне уменьшить вложенное выражение if 2) это увеличение моего объема, доступного моей переменной

, если Statement

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

}

Ответ 9

Из документации Apple:

Утверждение о защите

Оператор защиты используется для передачи программного управления из области действия, если один или несколько условий не совпадают.

Synatx:

guard condition else {
    statements
}

Преимущество:

1. Используя оператор guard, мы можем избавиться от глубоко вложенных условностей, единственной целью которых является проверка набора требований.

2. Он был разработан специально для выхода из метода или функции раньше.

, если вы используете, если ниже приведен код, как он выглядит.

  let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

        if error == nil {
            if let  statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 {
                if let data = data {

                    //Process Data Here.
                    print("Data: \(data)")

                } else {
                    print("No data was returned by the request!")
                }
            } else {
                print("Your request returned a status code other than 2XX!")
            }
        } else {
            print("Error Info: \(error.debugDescription)")
        }
    }
    task.resume()

Используя защиту, вы можете передать управление из области действия, если одно или несколько условий не выполнены.

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

            /* GUARD: was there an error? */
            guard (error == nil) else {
                print("There was an error with your request: \(error)")
                return
            }

            /* GUARD: Did we get a successful 2XX response? */
            guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 else {
                print("Your request returned a status code other than 2XX!")
                return
            }

            /* GUARD: was there any data returned? */
            guard let data = data else {
                print("No data was returned by the request!")
                return
            }

            //Process Data Here.
            print("Data: \(data)")
}
task.resume()

Ссылка:

1. Swift 2: выходите раньше с охраной 2. Udacity 3. Отчет о защите

Ответ 10

Как и оператор if, guard выполняет инструкции, основанные на логическом значении выражения. В отличие от оператора if, инструкции охраны выполняются только в том случае, если условия не выполняются. Вы можете думать о том, что охранник больше похож на Assert, но вместо того, чтобы сбой, вы можете изящно выйти.

относятся к: http://ericcerney.com/swift-guard-statement/

Ответ 11

Это действительно действительно делает поток последовательности с несколькими поисками и опциями намного более краткими и понятными и уменьшает количество случаев, если вложенность. См. Сообщение Эрика Садун при замене Ifs..... Может увлечься, пример ниже:

    let filteredLinks = locationsLinkedToList.filter({$0.actionVerb == movementCommand})
    guard let foundLink = filteredLinks.first else {return ("<Person> cannot go in that direction.", nil, nil)}
    guard filteredLinks.count == 1 else {return ("<Person> cannot decide which route to take.", nil, nil)}
    guard let nextLocation = foundLink.toLocation else {return ("<Person> cannot go in that direction.", nil, nil)}

Посмотрите, есть ли это.

Ответ 12

Проще говоря, он предоставляет способ проверки полей перед выполнением. Это хороший стиль программирования, поскольку он повышает читаемость. На других языках это может выглядеть так:

func doSomething() {
    if something == nil {
        // return, break, throw error, etc.
    }
    ...
}

Но поскольку Swift предоставляет вам дополнительные опции, мы не можем проверить, присваивает ли значение nil и значение переменной. Напротив, if let проверяет, что он не равен нулю и назначает переменную для хранения фактического значения. Здесь guard входит в игру. Это дает вам более сжатый способ выхода из предыдущих вариантов использования.

Ответ 13

Источник: https://thenucleargeeks.com/2019/05/09/guard-in-swift/

Давайте посмотрим на пример, чтобы понять это ясно

Пример 1:

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

В приведенном выше примере мы видим, что 3 больше 2, и оператор внутри предложения guard else пропускается, и выводится True.

Пример 2:

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

В приведенном выше примере мы видим, что 1 меньше 2, и оператор внутри предложения guard else выполняется, и выводится False с последующим возвратом.

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: "")

В приведенном выше примере мы используем guard let, чтобы развернуть опции. В функции getName мы определили переменную типа string myName, которая является необязательной. Затем мы используем guard let, чтобы проверить, равна ли переменная myName нулю или нет, если не присвоено имя и еще раз проверить, имя не пусто. Если оба условия удовлетворены, т.е. Истинно, блок else будет пропущен и выведите "Условия выполнены с именем".

В основном мы здесь проверяем две вещи, разделенные запятой, сначала разворачиваем и необязательно, и проверяем, удовлетворяет ли это условию или нет.

Здесь мы ничего не передаем функции, т.е. Пустой строке, и, следовательно, Условие false - это print.

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" в функцию, и вы можете видеть, что вывод печатается "Условие выполнено Hello".