Глава 2 · Переменные и значения
Имена и области видимости
К переменной, константе, подпрограмме или типу программа обращается по имени, но имя действует не везде. Область видимости очерчивает ту часть исходного текста, где объявление доступно; для обращения из другого файла к ней добавляются PUBLIC или PRIVATE и явный IMPORT.
Запись имени
Первым символом имени служит латинская буква ASCII или подчёркивание; далее допускаются такие же буквы, цифры и подчёркивание. Например, count, total_price и item2 соответствуют этим правилам. Имя не может начинаться с цифры или содержать пробел. Русские буквы допускаются в строках и комментариях, но не в пользовательских именах.
Регистр букв не различается: score, Score и SCORE обозначают одно имя. Объявление с другим регистром не создаёт новую переменную.
Ключевые слова зарезервированы, за исключением LINE: это слово допускается как имя в объявлении и выражении. В начале инструкции LINE также обозначает графический оператор, поэтому для переменной предпочтительно другое имя.
Имя типа DICTIONARY тоже зарезервировано, хотя и обозначает тип, а не оператор. Его нельзя использовать как имя переменной, константы, параметра, процедуры, функции, пользовательского типа, поля или метода; запрет регистронезависим. Синтаксис AS DICTIONARY(тип ключа, тип значения) при этом сохраняется. Подробности — в статье Словарь DICTIONARY.
Точка отделяет получателя от имени поля или метода: point.X, err.Code. Она не входит в имя переменной point или err.
Границы доступности
Имя, объявленное в некоторой области, действует в ней самой и во вложенных областях. За пределами блока нельзя обратиться к его переменной, а вызывающий код не имеет доступа к локальной переменной подпрограммы. Если имя недоступно, компилятор рассматривает обращение к нему как обращение к неизвестному имени.
Между файлами действует отдельное ограничение: объявление другого модуля доступно только с учётом PUBLIC и PRIVATE и явного IMPORT. Глобальное имя одного модуля автоматически не распространяется на все файлы проекта.
Переменные верхнего уровня
Имя, объявленное на верхнем уровне файла, называют глобальным в пределах модуля: подпрограммы этого модуля и методы его пользовательских типов читают и изменяют ту же переменную.
До проверки тел подпрограмм верхнего уровня компилятор собирает глобальные объявления всего файла, поэтому обращение из тела подпрограммы к переменной, объявленной ниже её заголовка, допустимо:
SUB Increase()
count = count + 1
END SUB
DIM count AS INTEGER = 4
Increase()
PRINT count
Результат:
5
Начальные значения задаются при выполнении объявлений: в примере DIM выполняется до вызова Increase. Правило доступа к поздним глобальным объявлениям относится к телам подпрограмм; в последовательности инструкций верхнего уровня обращение к имени до его объявления недопустимо.
Параметры и локальные переменные
Параметры и переменные внутри SUB или FUNCTION относятся к соответствующему вызову: при новом вызове создаются новые локальные значения. Передача исходной переменной через BYREF подчиняется правилам вызовов.
Вложенная подпрограмма может обращаться к доступным переменным внешней подпрограммы, а сохранённое функциональное значение удерживает доступ к ним и после завершения внешнего вызова. Такое сочетание функции и захваченных переменных называют замыканием; подробности приведены в главе процедур и функций.
Имена внутри блоков
Ветви IF и SELECT CASE, тела циклов и блоки TRY, CATCH и FINALLY создают отдельные области видимости. Вложенный блок может обращаться к доступным именам внешнего блока, но объявленные внутри имена за его пределами недоступны:
DIM total AS INTEGER = 0
IF TRUE THEN
DIM part AS INTEGER = 3
total = total + part
END IF
PRINT total
Результат:
3
После END IF имя total доступно, а имя part уже недоступно. Соседние ветви могут независимо объявлять одинаковые локальные имена.
FOR создаёт собственный счётчик, доступный внутри цикла, и не переиспользует предварительно объявленную одноимённую переменную. Отдельный DIM перед FOR не нужен, а после NEXT имя счётчика недоступно.
Конструкция CATCH err сама объявляет переменную err типа ERROR только для чтения. Имя доступно в этом CATCH и его вложенных блоках, но не в TRY, соседнем FINALLY и после END TRY; полный договор приведён в разделе объявления переменной CATCH.
Повторные имена и поля записи
Повторно объявить переменную в той же области нельзя. Также запрещено перекрывать во вложенной области доступное имя внешней переменной или константы. Это относится и к параметрам: если в модуле есть глобальная переменная count, параметру нужно дать другое имя. Запрет действует и тогда, когда глобальное объявление расположено ниже заголовка подпрограммы.
Имена переменных и подпрограмм учитываются раздельно, поэтому совпадение имени переменной или константы с пользовательской SUB либо FUNCTION вызывает предупреждение MB2045. Запуск оно не запрещает, но разные имена позволяют различать значение и вызов.
Поля TYPE принадлежат записи, и регистр букв в их именах не учитывается. Снаружи обращение к полю содержит получателя, например point.X; в методе собственное поле записывается через SELF.X, поскольку одного имени поля без SELF недостаточно.
Диагностика
| Код | Условие | Исправление |
|---|---|---|
| MB2001 | Обычное имя не объявлено или недоступно в текущей области. | Проверить написание и место объявления. |
| MB2002 | Повторное объявление в той же области, в том числе с другим регистром. | Удалить повтор или выбрать другое имя. |
| MB2016 | Переменная или параметр перекрывает доступное внешнее имя. | Дать новому объявлению отдельное имя. |
| MB2010 | Запись в константу или значение только для чтения, включая передачу BYREF. | Для изменяемых данных использовать переменную DIM. |
| MB2017 | В DIM опущены и тип, и начальное выражение. | Указать тип после AS или начальное выражение. |
| MB2003 | Тип записываемого значения несовместим с типом получателя. | Проверить типы. Для передачи функции как значения указывать саму функцию. |
| MB2044 | Неизвестное голое имя в методе совпало с полем текущего TYPE. | Указать получателя SELF. |
| MB2023 | Запись не содержит указанного поля. | Проверить имя; для TYPE сообщение может предложить близкое имя поля. |
| MB2045 | Имя переменной или константы совпадает с пользовательской подпрограммой. | Предупреждение: выбрать разные имена для значения и подпрограммы. |
Неизвестный вызов, в отличие от обычного имени, получает MB2005. Отказы доступа к закрытым объявлениям другого файла описаны в статье о доступности в модуле.