11 · Процедуры и функции
Оператор FUNCTION
Вычисление, которое повторяется в разных местах программы, удобно вынести под отдельное имя и получать его результат как значение. Для этого служит FUNCTION: объявление задаёт параметры и тип результата, а каждый вызов возвращает значение этого типа.
Объявление и прямой вызов
Функция отделяет повторяемое вычисление от места его использования. Объявление начинается ключевым словом FUNCTION, продолжается именем, необязательным списком параметров и типом результата после AS, а завершается END FUNCTION. Тип после AS определяет результат каждого успешного вызова.
FUNCTION <имя>(⟦<список параметров>⟧) AS <тип результата>
<инструкции>
END FUNCTION<имя>(⟦<список аргументов>⟧)Объявление доступно на верхнем уровне программы и внутри другой процедуры или функции. Объявления обрабатываются до вызовов, поэтому верхнеуровневый вызов может находиться раньше текста объявления. Локальная подпрограмма видна в своём внешнем теле и может захватывать доступные параметры и локальные переменные; внешняя локальная переменная должна быть объявлена раньше текста вложенного объявления. Графический режим не требуется.
Параметры
Список параметров содержит объявления через запятую. Каждый параметр задаёт имя и тип после AS; пустой список допустим. Список аргументов содержит выражения в том же порядке, и тип аргумента должен совпадать с типом параметра либо допускать предусмотренное языком преобразование.
<имя параметра> AS <тип параметра>BYVAL <имя параметра> AS <тип параметра>BYREF <имя параметра> AS <тип параметра>BYVAL применяется по умолчанию и передаёт независимую копию значения. Это правило действует для чисел, строк, массивов, TYPE, DICTIONARY и HASHSET. Вложенные изменяемые данные также копируются: изменение элемента массива или коллекции внутри параметра не меняет данные вызывающего кода. Аргумент фиксируется сразу после своего вычисления, до вычисления следующих аргументов. BYREF, напротив, явно связывает параметр с исходной переменной; изменение через такой параметр видно вызывающему коду. Функциональные значения с захватами и внешние ресурсы этим правилом автоматически не дублируются.
BYREF связывает параметр с переменной; массивная переменная записывается с обязательным суффиксом []. Тип должен точно совпадать; преобразование аргумента не допускается. Поле записи, элемент массива и вычисляемое выражение не являются допустимым аргументом BYREF. Передача CONST через BYREF отвергается диагностикой MB2010; для изменяемого аргумента используйте обычную переменную DIM.
Тип результата определяет значение вызова. Выражение RETURN должно иметь совместимый тип. Обычные типы, массивные типы и функциональные типы допустимы в параметрах и результате; STRING * N в этих местах не поддерживается.
Массивный результат и функциональный тип
Возвращаемый массивный тип не имеет собственного имени, поэтому квадратный суффикс ставится после типа элемента: AS STRING[] для одного измерения, AS INTEGER[,] для двух. В RETURN используется полное массивное выражение. Если это имя или поле, суффикс [] обязателен:
FUNCTION MakeFruits() AS STRING[]
DIM result[] AS STRING = SPLIT("яблоко,банан", ",")
RETURN result[]
END FUNCTION
DIM fruits[] = MakeFruits()
PRINT fruits[2]
PRINT MakeFruits()[2]Ожидаемый вывод — две строки банан. Вызов возвращает массив и не нуждается в добавочном пустом суффиксе. Запись [2] после вызова выбирает элемент результата.
Список безымянных типов параметров функционального значения сохраняет круглые скобки. Например, FUNCTION(STRING[]) AS INTEGER — тип функции с одномерным массивным аргументом и целочисленным результатом; FUNCTION() AS STRING[] — тип функции без аргументов, возвращающей массив. Это не запись DIM массива с суффиксом после типа: массивная переменная объявляется только со скобками после имени.
Возврат результата
RETURN с выражением вычисляет результат и завершает текущий вызов. Если исполнение достигает END FUNCTION без результата, возникает MB3006. Вызов функции отдельной инструкцией допускается: результат отбрасывается.
Функция как значение
Функцию без BYREF можно сохранить в переменной, передать другой функции или вернуть как результат. Для этого объявляется функциональная переменная, в которую записывается имя функции.
DIM <переменная> AS FUNCTION(⟦<типы параметров>⟧) AS <тип результата><переменная> = <имя функции><переменная>(⟦<список аргументов>⟧)В функциональном типе перечисляются типы параметров без имён; сигнатура должна совпадать. Имя без скобок обозначает функциональное значение, а вызов требует скобок. Функция с BYREF допускает прямые вызовы, но не может образовать функциональное значение. Неинициализированная функциональная переменная не содержит вызываемой функции.
Обе формы вызова дают один результат:
FUNCTION Square(value AS INTEGER) AS INTEGER
RETURN value * value
END FUNCTION
PRINT Square(5)
DIM operation AS FUNCTION(INTEGER) AS INTEGER
operation = Square
PRINT operation(6)Программа выводит:
25
36В первом случае имя стоит в вызове напрямую. Во втором сначала сохранено функциональное значение, а затем вызвано через переменную operation; вычисление выполняется то же самое, меняется только аргумент.
Параметры-массивы
Именованный параметр массива записывается со скобками после имени; AS задаёт тип элемента. Одна запятая внутри суффикса задаёт два измерения. Модификаторы BYVAL и BYREF сохраняют назначение:
<имя параметра>[] AS <тип элемента>BYVAL <имя параметра>[] AS <тип элемента>BYREF <имя параметра>[] AS <тип элемента><имя параметра>[,] AS <тип элемента>В теле подпрограммы и при вызове массивное имя требует [] для передачи массива целиком; индекс выбирает элемент. Например:
SUB ShowBasket(values[] AS STRING)
PRINT values[2]
END SUB
DIM fruits[] AS STRING = SPLIT("яблоко,банан", ",")
ShowBasket(fruits[])Ожидаемый вывод — банан. Скобки вызова ShowBasket круглые, суффикс аргумента fruits — квадратный. BYREF для массива принимает массивную переменную с [] и точно совпадающим типом и рангом; индексированный элемент и поле записи этим правилом не становятся допустимыми аргументами BYREF.
Диагностика
MB2004 означает неверное число аргументов; MB2003 — несовместимый тип; MB2005 — неизвестное вызываемое имя. MB2028 возникает для недопустимого аргумента BYREF. Повторное имя в одной области даёт MB2002; запрещённое перекрытие внешнего имени — MB2016. Избыточная рекурсия даёт MB3011 во время выполнения.
MB2007 означает RETURN без выражения в FUNCTION. MB2029 запрещает использование функции с BYREF как значения. MB3006 означает завершение функции без возвращённого значения; MB3009 — вызов пустого функционального значения.
См. также
SUB · RETURN · Вызовы · Обработка массивов
Доступность в модуле
Перед объявлением верхнего уровня можно указать PUBLIC или PRIVATE. Без модификатора имя закрыто внутри файла. Модификатор PUBLIC открывает имя для файлов, которые явно импортируют текущий модуль. Он не меняет остальные правила объявления.
PUBLIC FUNCTION name(parameters) AS resultTypePRIVATE FUNCTION name(parameters) AS resultTypeВложенные объявления не получают модификатора. Подробнее: PUBLIC и PRIVATE и IMPORT.
Группа параметров одного типа
Если несколько соседних параметров имеют одинаковый тип, их имена можно перечислить перед общей частью AS. Например, first, second AS INTEGER равнозначно first AS INTEGER, second AS INTEGER. Явный BYREF или BYVAL перед первым именем действует на всю группу. Для изменения режима отдельного параметра завершите предыдущую группу указанием типа.
Возврат нескольких значений и примеры обращения к ним описаны на странице кортежей.