Фрагмент программного кода, к которому можно обратиться из другого места программы, называется методом. Данный раздел содержит особенности описания и использования методов.
Общая информация
При разработке программы часто возникает необходимость повторного использования какого-либо ее фрагмента. Для простого повторения одного и того же фрагмента кода несколько раз можно использовать цикл. А если этот фрагмент вызывается из разных мест программы, необходимо выделить программный код и оформить его специальным образом. Такой обособленный фрагмент кода называется метод. Метод может как возвращать значение, так и не возвращать ничего (подробнее).
Используемые определения
Для описания методов будут использоваться следующие термины:
-
Определение метода
Место в исходном коде, где создан метод.
-
Сигнатура метода
Уникальный идентификатор метода, состоящий из области видимости метода, модификатора, имени метода, списка параметров и типа возвращаемого значения.
-
Объявление метода
Часть определения метода, которая содержит его сигнатуру.
-
Имя метода
Идентификатор, расположенный после ключевого слова метод, используемый для его объявления и вызова.
-
Тело метода
Инструкции, расположенные между объявлением метода и символом ;, описывающим завершение метода.
-
Вызов метода
Место в тексте программы, где указывается имя метода с указанием фактических параметров и использованием результата работы, если метод возвращает значение.
-
Определение параметров и передача аргументов
- Параметр метода — это именованная переменная, через которую тело метода получает значение при вызове.
- Аргумент — это значение, которое указывается во время вызова метода.
- Передача параметров — это предоставление аргументов методу при его вызове.
-
Возврат значения
Передача вызывающему программному коду какого-либо значения при завершении работы метода. Метод не обязательно должен возвращать какое-либо значение.
Определение метода
Прежде чем использовать метод, его надо определить. Определение метода выглядит следующим образом:
@аннотация-видимости
метод имя-метода([параметр[, параметр[, ...]]])[: тип-возвращаемого-значения]
тело-метода
[возврат[ значение]]
;
Каждый параметр описывается следующим образом:
имя-параметра: тип-параметра[ = значение-по-умолчанию]
имя-параметра задает имя параметра в соответствии со стандартными правилами формирования имен.
тип-параметра указывает, соответственно, тип параметра (в том числе и составной).
значение-по-умолчанию является необязательным элементом описания параметра и позволяет указать значение по умолчанию, т. е. значение, которое будет присвоено параметру, если при вызове метода соответствующий аргумент пропущен. Не допускается пропускать аргумент, если для соответствующего параметра не указано значение по умолчанию. В качестве значения по у молчанию выступает любое выражение, которое может быть вычислено на этапе компиляции:
- Литералы (включая литералы коллекций) являются вычислимыми.
- Обращения к константам модулей являются вычислимыми.
конст МЕТРОВ_В_КИЛОМЕТРЕ: Число = 1000
метод МетровВКилометре(Сообщение: Строка = "В километре ", Число: Число = МЕТРОВ_В_КИЛОМЕТРЕ): Строка
возврат Сообщение + Число + " метров"
;
Операции над вычислимыми значениями являются вычислимыми, кроме следующих исключений:
- вызовы методов и обращения к свойствам,
- вызовы конструкторов.
конст МЕТРОВ_В_КИЛОМЕТРЕ: Строка = "1000"
метод СообщитьЧасовойПояс(Пояс: ЧасовойПояс = ЧасовойПояс.Текущий()): Строка
возврат "Текущий часовой пояс $Пояс"
;
метод МетровВКилометре(Число: Число = новый Число(МЕТРОВ_В_КИЛОМЕТРЕ)): Строка
возврат "В километре $Число метров"
;
Особенности передачи параметров
Переменные хранят ссылки на экземпляры. В методы передаются значения переменных. Таким образом можно в методе изменять состояние экземпляра, но нельзя изменить значение переменной, передаваемого в качестве аргумента метода.
метод ТестовыйМетод(Параметр: Число)
Параметр = 6
;
метод Скрипт(): Строка
пер ЧислоДляТеста = 5
ТестовыйМетод(ЧислоДляТеста)
пер ПослеВызова = "ДляТеста = $ЧислоДляТеста"
возврат ПослеВызова
;
В данном примере значение переменной ЧислоДляТеста в ме тоде Скрипт() будет равно 5 и до вызова метода ТестовыйМетод(), и после вызова этого метода. Такое поведение обеспечивает передача параметра «по значению».
Однако, если в метод передается экземпляр, который располагает методами для изменения своего содержимого, то ситуация будет немного другой. Рассмотрим пример:
метод ОчиститьМассив(Параметр: Массив<Число>)
Параметр.Очистить()
Параметр = [1, 2, 3]
;
метод Скрипт(): Строка
пер МассивДляТеста = [1, 2]
ОчиститьМассив(МассивДляТеста)
пер ПослеВызова = "ДляТеста = " + МассивДляТеста
возврат ПослеВызова
;
В этом примере до выполнения метода ОчиститьМассив() в массиве МассивДляТеста будет два значения: 1 и 2. После вызова метода ОчиститьМассив() в массиве не будет ни одного элемента. В то же время, если в методе ОчиститьМассив() мы попробуем присвоить параметру Параметр какое-либо значение, это не приведет к каким-либо изменениям аргумента (переменной МассивДляТеста).
Вызов метода с именованными параметрами
При вызове метода допускается передача не только аргументов в соответствии с их позицией в сигнатуре, то есть позиционных аргументов, но и передача аргументов вместе с их именами — именованных аргументов. Например:
метод Поделить(А: Число, Б: Число): Число
возврат А / Б
;
метод Скрипт()
Поделить(Б = 10, А = 0)
Поделить(А = 10, Б = 0)
;
Синтаксис:
имя-метода(имя-параметра-1 = значение, имя-параметра-2 = значение, ... , имя-параметра-N = значение)
Нумерация параметров в данном случае является условной, используется для отличия параметров друг от друга и не указывает на порядковый номер параметра при определении или при вызове метода.
Прежде всего, могут быть методы, которые не допускают использования позиционных параметров. В этом случае перед ними указывается аннотация @ИменованныеПараметры. Подробнее об аннотациях смотрите здесь.
Кроме того, в некоторых случаях данный способ параметризации имеет ряд преимуществ перед использованием позиционирования:
-
Передавать аргументы не обязательно в строгом порядке. Пользователю не требуется искать сигнатуру метода, чтобы вспомнить строгий порядок аргументов. Кроме того, если во время написания кода разработчик поменяет местами параметры в сигнатуре, в том числе параметры одного типа, это не приведет к ошибке во время компиляции или исполнения кода. Сравните:
метод Разделить(А: Число, Б: Число): Число
возврат А / Б
;
метод Скрипт()
Разделить(3, 2)
Разделить(А = 3, Б = 2)
Разделить(Б = 2, А = 3)
;
или:
метод РассчитатьСебестоимость(Цена: Число, Наценка: Число, Налог: Число): Число
возврат Цена - (Цена * Наценка / 100 + Цена * Налог / 100)
;
метод Скрипт()
РассчитатьСебестоимость(1, 10, 100)
РассчитатьСебестоимость(Налог = 1, Наценка = 10, Цена = 100)
;
-
Имена параметров отображаются сразу же при вызове метода. В таком случае не требуется искать сигнатуру метода, чтобы вспомнить, какой параметр что означает. См. пример выше или:
метод Сообщить(Сообщение: Строка, ПеревестиВВерхнийРегистр: Булево): Строка
если ПеревестиВВерхнийРегистр == Истина
возврат Сообщение.ВВерхнийРегистр()
иначе
возврат Сообщение
;
;
метод Скрипт()
Сообщить("Привет, мир!", Ложь)
Сообщить("Привет, мир!", ПеревестиВВерхнийРегистр = Истина)
;
-
Можно выборочно указывать только некоторые, наиболее важные параметры. Это может быть особенно удобным, когда в методе используется много необязательных, «служебных» параметров. Для них будут использоваться значения по умолчанию, которые указываются при определении метода. Кроме того, для некоторых параметров уже могут быть указаны значения по умолчанию. Так, если для метода РассчитатьСебестоимость() задать значения по умолчанию: для наценки — 10 (%), а для налога — 1 (%), то можно передавать только значение цены. Сравните:
метод РассчитатьСебестоимость(Налог: Число = 1, Наценка: Число = 10, Цена: Число): Число
возврат Цена - (Цена * Наценка / 100 + Цена * Налог / 100)
;
метод Скрипт()
РассчитатьСебестоимость(100)
РассчитатьСебестоимость(Цена = 100)
;
Смешанная параметризация
При вызове метода можно смешивать позиционную и именованную формы параметризации. Например:
метод РассчитатьСебестоимость(Налог: Число = 1, Наценка: Число = 10, Цена: Число): Число
возврат Цена - (Цена * Наценка / 100 + Цена * Налог / 100)
;
метод Скрипт()
РассчитатьСебестоимость(Налог = 1, Наценка = 10, Цена = 100)
РассчитатьСебестоимость(1, 10, Цена = 100)
;
При с мешанной параметризации действуют следующие правила:
- Если параметр со значением по умолчанию находится перед параметром с обязательным значением, то в вызове при опускании первого параметра требуется указать второй параметр в именованном виде.
- При вызове все позиционные параметры должны быть указаны до первого именованного параметра.
- Параметры со значениями по умолчанию, находящиеся в конце сигнатуры, можно опускать при вызовах.
метод РассчитатьСебестоимость(Налог: Число = 1, Наценка: Число, Цена: Число = 100): Число
возврат Цена - (Цена * Наценка / 100 + Цена * Налог / 100)
;
метод Скрипт()
РассчитатьСебестоимость(Наценка = 10)
РассчитатьСебестоимость(Наценка = 10, Цена = 100)
;
Разрешение неоднозначности
Неоднозначность в контексте вызова методов — это ситуация, когда невозможно однозначно определить, какую версию перегруженного метода следует выполнить при использовании име нованных аргументов. При разрешении неоднозначности действуют следующие правила:
-
Если под вызов в именованной форме подходит несколько методов, выдается ошибка неоднозначности:
метод Обработать(А: Число, Б: Строка): Строка
возврат"Версия 1: ${А}, ${Б}"
;
метод Обработать(Б: Строка, А: Число): Строка
возврат "Версия 2: ${А}, ${Б}"
;
метод Скрипт()
Обработать(10, "текст")
Обработать(А = 10, Б = "текст")
;
-
При объявлении методов проверка на возможную неоднозначность вызовов в именованной форме не производится, в отличие от позиционной:
метод Тест(Б: Строка, А: Число): Строка
возврат "Версия 1: ${А}, ${Б}"
;
метод Тест(А: Число, Б: Строка): Строка
возврат "Версия 1: ${А}, ${Б}"
;
метод Тест(А: Число, Б: Строка): Строка
возврат "Версия 1: ${А}, ${Б}"
;
-
Некоторые перегрузки метода не допускают использования именованной формы:
метод Конкатенация(А: Число, Б: Строка): Строка
возврат А.ВСтроку() + Б
;
метод Конкатенация(Б: Строка, А: Число): Строка
возврат А.ВСтроку() + Б
;
метод Скрипт()
Конкатенация(А = 10, Б = "текст")
;
-
При этом из нескольких перегрузок, которые соответствуют именованному вызову метода, будет выбрана перегрузка, у которой меньше всего аргументов:
метод Сообщить(Число: Число, Сообщение = "Это число: ", ПосчитатьДлину = Истина): Строка
если ПосчитатьДлину == Истина
возврат "Длина сообщения: ${(Сообщение+Число).Длина()}"
иначе
возврат Сообщение + " " + Число
;
;
метод Сообщить(Число: Число, ПосчитатьДлину: Булево): Строка
если ПосчитатьДлину == Истина
возврат "Длина сообщения: ${Число.ВСтроку().Длина()}"
иначе
возврат Число.ВСтроку()
;
;
метод Скрипт()
Сообщить(255)
Сообщить(255, Истина)
Сообщить(255, "Это число: ")
Сообщить(255, "Это число: ", Истина)
Сообщить(Число = 255, ПосчитатьДлину = Ложь)
;
Завершение метода и возвращаемое значение