Вас удивляет, что я посвящаю учебник простому дополнению в качестве guard
заявления? Я надеюсь, вы лучше поймете мое волнение в конце этого урока. В этом уроке я надеюсь убедить вас, что guard
— это не что иное, как избыточное дополнение к языку программирования Swift.
Минимизация сложности
Условные выражения являются фундаментальным компонентом каждого языка программирования. Objective-C и Swift не являются исключением из этого правила. Если вы планируете написать приложение любой сложности, условные обозначения будут пересекаться на вашем пути, их избежать не избежать.
К сожалению, условные обозначения часто являются самой причиной сложности. В частности, вложенные условные выражения могут привести к трудностям поиска ошибок, сложному для понимания коду и легко пропускаемым пограничным случаям.
Чтобы сводить вложенные операторы if
к минимуму, я часто использую следующий шаблон в Objective-C.
1
2
3
4
5
6
7
|
— (void)fetchListOfCustomers:(NSArray *)customers {
if (!self.reachable) return;
if (!self.connected) return;
if (!customers || ![customers count]) return;
…
}
|
Идея состоит в том, чтобы выручить как можно скорее. Операторы if
в этом примере представляют собой набор требований, которые необходимо выполнить перед выполнением остальной части тела метода.
Приведенный выше пример переводится в следующий, немного более сложный эквивалент.
1
2
3
4
5
6
7
|
— (void)fetchListOfCustomers:(NSArray *)customers {
if (self.reachable && self.connected) {
if (customers && [customers count]) {
…
}
}
}
|
Вы видите проблему, скрывающуюся в этом примере? Мы уже вложили два уровня в глубину, не сделав ничего интересного.
Легко перевести вышеуказанный шаблон в Swift. Синтаксис выглядит аналогично, но поскольку customers
являются необязательными, нам нужно развернуть аргумент customers
прежде чем мы сможем получить доступ к его значению.
1
2
3
4
5
6
7
|
func fetchListOfCustomers(customers: [Customer]?) {
if !reachable { return }
if !connected { return }
if let customers = customers where customers.count > 0 {
print(customers)
}
}
|
Выход рано
Swift 2 вводит guard
заявление. Он был разработан специально для выхода из метода или функции на ранней стадии. guard
утверждение идеально подходит для избавления от глубоко вложенных условных выражений, единственной целью которых является проверка набора требований. Взгляните на обновленный пример, в котором я заменил каждый оператор if
новым оператором guard
.
1
2
3
4
5
6
7
|
func fetchListOfCustomers(customers: [Customer]?) {
guard reachable else { return }
guard connected else { return }
guard let customers = customers where customers.count > 0 else { return }
print(customers)
}
|
Есть несколько вещей, которые стоит отметить. Давайте начнем с синтаксиса.
Синтаксис
Ключевое слово guard
подчеркивает, что мы проверяем требование. Мы защищаемся от чего-то. В этом примере мы явно проверяем, reachable
ли и connected
они. Если это не так, то мы покидаем метод рано. Дело в том, что синтаксис более точен в отношении требований, чем обычный оператор if
.
Выход
Обратите внимание, что у оператора guard
всегда есть предложение else
. Предложение else
выполняется, если условие оператора guard
оценивается как false
. Использование guard
имеет больше смысла, когда вы проверяете требования.
В предложении else
вы должны перенести управление за пределы области действия, в которой появляется оператор guard
. Мы используем оператор return
в приведенном выше примере, но вы можете, например, использовать оператор continue
если вы находитесь в цикле или генерируете ошибку. Взгляните на обновленный пример ниже, в котором мы выкидываем ошибку в предложении else
. Обратите внимание на ключевое слово throws
в объявлении метода, которое указывает, что fetchListOfCustomers(_:)
является методом throwing.
1
2
3
4
5
6
7
|
func fetchListOfCustomers(customers: [Customer]?) throws {
guard reachable else { throw APIError.APIErrorUnreachable }
guard connected else { throw APIError.APIErrorNotConnected }
guard let customers = customers where customers.count > 0 else { throw APIError.APIErrorNoCustomers }
…
}
|
мощный
guard
утверждение столь же мощно, как и утверждение if
. Вы можете использовать необязательные привязки, и даже использование предложений where
, представленных в Swift 1.2, разрешено. Я уверен, что вы согласны с тем, что пример легко понять, исключая ненужные вложенные условия.
Сфера
Важным отличием операторов if
является область действия переменных и констант, которым присваиваются значения с использованием необязательной привязки. В приведенном выше примере константе customers
было присвоено значение с использованием необязательной привязки. Постоянная для customers
доступна из области, в которой появляется заявление guard
. Это важная деталь и одно из ключевых преимуществ использования guard
.
Вывод
Если вы думали, что guard
— это простая вариация заявления Свифта, то, надеюсь, я убедил вас в обратном. Хотя в большинстве ситуаций заявления по-прежнему будут вашим предпочтительным инструментом, в определенных ситуациях у guard
есть ряд преимуществ. Это особенно верно, если используется в сочетании с обработкой ошибок, которая также была представлена в Swift 2.