varfound = false
foriteminarray {
ifitem == search {
count++
continue
found = true
print("Found!")
}
}
В этом примере цикл переберет все элементы, и после его выполнения переменная count будет равна количеству элементов в массиве array, удовлетворяющих условию поиска search. Но переменная found никогда не примет значение true, и функция print() также не сработает. Как только исполнение программы дойдет до оператора continue, шаг цикла завершится, и начнется следующий шаг с новым элементом item.
Объявление и вызов функций
При объявлении функции можно задать одно или несколько именованных типизированных значений, которые будут ее входными данными (или параметрами), а также тип значения, которое функция будет возвращать в качестве результата (или возвращаемый тип).
У каждой функции должно быть имя, которое отражает решаемую задачу. Чтобы воспользоваться функцией, ее нужно "вызвать", указав имя и входные значения (аргументы), соответствующие типам параметров этой функции. Аргументы функции всегда должны идти в том же порядке, в каком они были указаны при объявлении функции.
В приведенном ниже примере функция называется greet(person:), потому что это отражает ее задачу – получить имя пользователя и вежливо поздороваться. Для этого задается один входной параметр типа String под названием person, а возвращается тоже значение типа String, но уже содержащее приветствие:
funcgreet(person: String) ->String {
let greeting = "Hello, " + person + "!"
return greeting
}
Вся эта информация указана в объявлении функции, перед которым стоит ключевое слово func. Тип возвращаемого значения функции ставится после результирующей стрелки -> (это дефис и правая угловая скобка).
Из объявления функции можно узнать, что она делает, какие у нее входные данные и какой результат она возвращает. Объявленную функцию можно однозначно вызывать из любого участка кода:
print(greet(person: "Anna"))
// Prints "Hello, Anna!"
print(greet(person: "Brian"))
// Prints "Hello, Brian!"
Функция greet(person:) вызывается, принимаязначениетипа String, котороестоитпослеимени person, напримервоттак - greet(person: "Anna"). Поскольку функция возвращает значение типа String, вызов функции greet(person:) может быть завернут в вызов для функции print(_:separator:terminator:), чтобы напечатать полученную строку и увидеть возвращаемое значение (см. выше).
У print(_:separator:terminator:) нет ярлыка для первого аргумента, и его другие аргументы являются опциональными, поскольку имеют дефолтное значение (по умолчанию). Эти вариации синтаксиса функции рассматриваются ниже в Ярлыки аргументов и имена параметров функций и Значения по умолчанию для параметров.
Тело функции greet(person:) начинается с объявления новой константы типа String под названием greeting, и устанавливается простое сообщение-приветствие. Затем это приветствие возвращается в точку вызова функции с помощью ключевого слова return. После выполнения оператора returngreeting функция завершает свою работу и возвращает текущее значение greeting.
Функцию greet(person:) можно вызывать многократно и с разными входными значениями. В примере выше показано, что будет, если функцию вызвать с аргументом "Anna" и со значением "Brian". В каждом случае функция возвратит персональное приветствие.
Чтобы упростить код этой функции, можно записать создание сообщения и его возврат в одну строку:
funcgreetAgain(person: String) ->String {
return"Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// Выведет "Helloagain, Anna!"
СИНТАКСИС
funcимяФункции (входные_параметры) -> тип {
// тело функции
}
имяФункции— имя объявляемой функции, по которому она сможет быть вы- звана.
входныепараметры—списокаргументовфункциисуказаниемихименитипов.
Тип—типданныхзначения,возвращаемогофункцией.Еслифункцияничегоне возвращает, то данный элемент может бытьопущен.
Функция может принимать аргументы (параметры) в качестве входных значений и возвращать результат своей работы (возвращаемое значение). И для входных, и для возвращаемого значений должны быть определены типы данных. Рассмотрим пример. Требуется многократно производить сложение двух целочисленных чисел и возвращать полученный результат в виде значения типа Int. Правильным подходом будет объявление функции, производящее данные действия. В качестве входного аргумента будут служить складываемые числа, а результат операции будет возвращаемым значением. Конечно, это очень простой пример, и куда лучше написать a+b для сложения двух операндов, а не городить функцию. Но для рассмотрения учебного материала он подходит как нельзя лучше. Но если вычисляемое выражение значительно сложнее, например a+b*b+a*(a+b)*(a+b), то создание функции будет оправданно.
Входные аргументы
Реализуем описанную выше задачу, но при этом исключим из неетребование возвращать результат сложения. Пусть результат операции выводится на отладочную консоль (листинг 15.2).
Листинг 15.2
funcsumTwoInt(a: Int, b: Int){
print("Результат операции - \(a+b)")
}
sumTwoInt(a: 10, b: 12)
Консоль
Результат операции - 22
Функция sumTwoInt(a:b:) имеет два входных параметра типа Int — a и b. Обратите внимание, что все входные аргументы должны иметь значения, поэтому попытка вызвать функцию, передав в нее лишь один
Изменяемые копии входных аргументов
Все входные параметры функции — константы. При попытке изменения их значения внутри тела функции происходит ошибка. При необходимости изменения переданного входного значения внутри функции потребуется создать новую переменную и присвоить переданное значение ей (листинг 15.6).
Листинг 15.6
funcreturnMessage(code: Int, message: String) -> String {
varmutableMessage = message
mutableMessage += String(code)
return mutableMessage
}
varmyMessage = returnMessage(code: 200, message: "Кодсообщения - ")
ФункцияreturnMessage(code:message:) получаетнавходдвааргумента: code и message. В ее теле создается изменяемая копия message, которая без каких-либо ошибок модифицируется, после чего возвращается.
Сквозные параметры
Приведенный способ модификации значений аргументов позволяет получать доступ к изменяемому значению только в пределах тела самой функции. Для того чтобы была возможность модификации входных аргументов с сохранением измененных значений после окончания работы функции, необходимо использовать сквозные параметры. Чтобы преобразовать входной параметр в сквозной, перед описанием его типа необходимо указать модификатор inout. Сквозной параметр передается в функцию, изменяется в ней и сохраняет свое значение при завершении работы функции, заменяя собой исходное значение. При вызове функции перед передаваемым значением аргумента необходимо ставить символ амперсанд (&) , указывающий на то, что параметр передается по ссылке.
Функция в листинге 15.7 обеспечивает обмен значениями двух внешних параметров.
Листинг 15.7
funcchangeValues(_ a: inoutInt, _ b: inoutInt) -> () {
let tmp = a
a = b
b = tmp
}
var x = 150, y = 45
changeValues(&x, &y)
x // 45
y // 150
Функция принимает на входе две переменные, a и b. Эти переменные
передаются в функцию как сквозные параметры, что позволяет изменить их значения внутри функции и сохранить эти изменения после завершения ее работы.
ПРИМЕЧАНИЕ В качестве сквозного параметра может выступать только переменная. Константы или литералы нельзя передавать, так как они являются неизменяемыми.
Вы можете использовать возвращаемое некоторой функцией значение в качестве значения входного аргумента другой функции. Самое важное, чтобы тип возвращаемого значения функции совпадал с типом входного параметра.
В листинге 15.8 используется объявленная ранее функция returnMessage(code:message:), возвращающая значение типа String.
Листинг 15.8
// используем функцию в качестве значения
print( returnMessage(code: 400, message: "Сервернедоступен. Код
сообщения - ") )
Консоль
Сервер недоступен. Код сообщения - 400
Уже известная нам функция print(_:) принимает на входе строковый литералтипа String. ТаккакфункцияreturnMessage(code:message:) возвращает значение этого типа, она может быть указана в качестве входного аргумента для print(_:).
Входной параметр с переменным числом аргументов
В некоторых ситуациях необходимо, чтобы функция получала неизвестное заранее число однотипных аргументов. Мы уже встречались с таким подходом при использовании Array(arrayLiteral:), когда заранее неизвестно, сколько элементов будет содержать аргумент arrayLiteral. Такой тип входного аргумента называется вариативным. Вариативный аргумент обозначается в списке входящих параметров с указанием оператора диапазона ... сразу после типа. Значения для этого аргумента при вызове функции задаются через запятую. Рассмотрим пример из листинга 15.9. Представьте, что удаленный сервер на каждый запрос отправляет вам несколько ответов. Каждый ответ — это целое число, но их количество может быть различным. Вам необходимо написать функцию, которая принимает на входе все полученные ответы и выводит их на консоль.
Листинг 15.9
funcprintRequestString(codes: Int...) -> () {
varcodesString = ""
for oneCode in codes {
codesString += String(oneCode) + " "
}
print("Полученыответы — \(codesString)")
}
printRequestString(codes: 600, 800, 301)
printRequestString(codes: 101, 200)
Консоль
Получены ответы — 600 800 301
Получены ответы — 101 200
Параметр codes может содержать произвольное количество значений
указанного типа. Внутри функции он трактуется как последовательность (Sequence), поэтому его можно обработать с помощью конструкции for-in. У одной функции может быть только один вариативный параметр, и он должен находиться в самом конце списка входных аргументов.
Функция может возвращать значения любого типа данных. Отдельно отмечу, что и кортежи могут быть использованы для этого, так как с их помощью можно с легкостью вернуть сразу несколько значений (возможно, именно этого вам не хватало в других языках программирования, лично мне не хватало ). Представленная в листинге 15.10 функция принимает на вход код ответа сервера и, в зависимости от того, к какому диапазону относится переданный код, возвращает кортеж с его описанием.
Листинг 15.10
funcgetCodeDescription(code: Int) -> (Int, String){
let description: String
switch code {
case 1...100:
description = "Error"
case 101...200:
description = "Correct"
250 Часть IV. Основные возможности Swift
default:
description = "Unknown"
}
return (code, description)
}
getCodeDescription(code: 150) // (150, "Correct")
В качестве типа возвращаемого значения функци и getCodeDescription(code:) указан тип кортежа, содержащего два значения: код и его описание. Функцию getCodeDescription(code:) можно улучшить, если указать не просто тип возвращаемого кортежа, а названия его элементов (прямо в типе возвращаемого функцией значения) (листинг 15.11).
Листинг 15.11
funcgetCodeDescription(code: Int)
-> (code: Int, description: String){
let description: String
switch code {
case 1...100:
description = "Error"
case 101...200:
description = "Correct"
default:
description = "Unknown"
}
return (code, description)
}
let request = getCodeDescription(code: 45)
request.description // "Error"
request.code // 45
Полученное в ходе работы getCodeDescription(code:) значение записывается в константу request, у которой появляются свойства description и code, что соответствует именам элементов возвращаемого кортежа.
Значение по умолчанию для входного аргумента
Напомню, что все входные аргументы должны обязательно иметь значения. Ранее для этого мы указывали их при вызове функции. Но существует возможность определить значения по умолчанию, которые позволяют не указывать значения при вызове. Другими словами: если вы передали значение входного аргумента, то оно будет использовано в теле функции; если вы не передали значение аргумента, для него будет использовано значение по умолчанию. Значение по умолчанию указывается при объявлении функции в списке входных аргументов для каждого параметра отдельно.
Доработаем объявленную ранее функцию returnMessage(code:message:) таким образом, чтобы была возможность не передавать значение аргумента message. Для этого укажем значение по умолчанию (листинг 15.12).
Листинг 15.12
funcreturnMessage(code: Int, message: String = "Код - ") -> String {
varmutableMessage = message
mutableMessage += String(code)
return mutableMessage
}
returnMessage(code: 300) //"Код - 300"
Каквыможетевидеть, привызовеreturnMessage(code:message:) не передаетсязначениедляаргумента message. Это стало возможным благодаря установке значения по умолчанию "Код - " в списке входных параметров.
Внешние имена входных аргументов
Аргументы a и b функции sumTwoInt(a:b:) используются как при вызове функции, так и в ее теле. Swift позволяет указать внешние имена параметров, которые будут использоваться при вызове функции
Листинг 15.3
funcsumTwoInt(num1 a: Int, num2 b: Int){
print("Результат операции - \(a+b)")
}
sumTwoInt(num1: 10, num2: 12)
Теперь при вызове функции sumTwoInt(num1:num2:) необходимо указывать значения не для безликих a и b, а для более-менее осмысленных num1 и num2. Данный прием очень полезен, так как позволяет задать понятные и соответствующие контексту названия входных аргументов, но при этом сократить количества кода в теле, используя краткие внутренние имена. Если внешнее имя заменить на символ нижнего подчеркивания (_), то при вызове функции имя параметра вообще не потребуется указывать
Листинг 15.4
funcsumTwoInt(_ a: Int, _ b: Int){
print("Результат операции - \(a+b)")
}
sumTwoInt(10, 12)
Примечание Внешние имена могут быть заданы для произвольных аргументов, не обязательно указывать их для всех.