Найти тему
MQL-программирование

Синтаксис языка программирования MQL. Область видимости переменных

Оглавление

Теперь, когда мы уже познакомились с различными конструкциями языка, такими как операторы выбора, циклы, а также функции, вернемся к теме, которую мы рассматривали несколько ранее — к переменным.

Если быть точнее, то мы восполним один пробел в понимании переменных, который я намеренно пропустил. На том этапе, до рассмотрения прочих конструкций языка эта тема была бы не совсем понятна. Итак, приступим.

Область видимости переменных

Из самого понятия "переменная" напрашивается вывод, что это некая сущность, которая имеет особенность изменяться. На самом деле, помимо того, что переменные способны хранить различные значения и изменять их в процессе выполнения программы, они, как и любые объекты в языке программирования MQL создаются и уничтожаются.

Создание переменной происходит явно при ее объявлении или инициализации, а вот уничтожением переменных занимается компилятор и делает это неявно, скрытно от разработчика. Наша задача сегодня — разобраться с этим процессом — моментом уничтожения переменных, после которого они становятся недоступны.

Но, для повторения пройденного ранее материала, давайте вернемся к моменту создания переменных.

Рис. 1. Пример объявления и инициализации переменных.
Рис. 1. Пример объявления и инициализации переменных.

На примере выше приведено объявление и инициализация нескольких переменных. Напомню, что объявление переменной всегда начинается с объявления типа данных, значение которого будет хранить данная переменная. Это необходимо для того, чтобы компилятор на этапе сборки нашей программы смог корректно определить, сколько памяти потребуется выделить переменной и соответственно распределить свободную память компьютера.

После указания типа данных следует указание имени переменной, под которой она будет доступна далее в программе. После указанного имени переменной возможно сразу же присвоение ей начального значения (инициализация переменной начальным значением).

Если переменная инициализированная начальным значением, то компилятор, в момент выделения памяти для хранения значения переменной, сразу же запишет это значение в соответствующую ячейку памяти компьютера. Если переменная объявлена, но не инициализирована начальным значением, то компилятор не заботится о значении, которое хранится в выделенной ячейке памяти.

В результате этого значение переменной не определено, т.к. в выделенном участке памяти в общем случае может содержаться "мусор" — значения каких-либо переменных, которые ранее занимали данный участок памяти компьютера.

Итак, после объявления переменной, имя переменной становится доступно в программе. Если попытаться обратиться к переменной, которая объявлена ниже в программном коде, то компилятор сгенерирует ошибку компиляции — undeclared identifier, что означает попытку обратиться к необъявленной переменной.

Рис. 2. Сообщение об ошибке компиляции.
Рис. 2. Сообщение об ошибке компиляции.

Из этого можно сделать простой вывод — объявление переменной есть момент ее создания, начиная с которого, переменная становится доступной внутри программы.

Но, до какого момента времени она существует?

Локальные переменные

Переменные, которые объявлены внутри любого оператора (условного, оператора выбора, составного оператора или оператора цикла) действительна только в пределах этого оператора.

Давайте сразу перейдем к примерам.

Рис. 3. Пример объявления локальной переменной.
Рис. 3. Пример объявления локальной переменной.

Обратите внимание на то, что переменная i была инициализирована внутри оператора цикла for. Это значит, что за пределами данного оператора, имя этой переменной будет недоступно. Так, попытка обращения к переменной i после закрытия составного оператора, представляющего собой тело цикла (после закрытия фигурной скобки) приведет к ошибке компиляции, в чем можно убедиться, попытавшись скомпилировать данный пример:

Рис. 4. Пример обращения к значению переменной вне ее области видимости.
Рис. 4. Пример обращения к значению переменной вне ее области видимости.

Таким образом, время жизни локальной переменной — блок, внутри которого была объявлена переменная. Внутри блока переменная будет доступна с момента ее объявления до завершения текущего блока.

При этом, если внутри блока, который является областью видимости переменной, будут вложенные блоки, то внутри них наша переменная будет доступна, как ни в чем не бывало:

Рис. 5. Пример получения доступа к значению локальной переменной из вложенного блока.
Рис. 5. Пример получения доступа к значению локальной переменной из вложенного блока.

Перекрытие переменных

Давайте рассмотрим следующий пример:

Рис. 6. Пример перекрытия переменной.
Рис. 6. Пример перекрытия переменной.

Обратите внимание на тот момент, что переменная i объявлена в программе два раза! Первое объявление в самом начале служебной функции OnTick(), второе — внутри оператора цикла for.

В этом случае произойдет так называемое перекрытие переменных, при котором переменная, которая была объявлена ранее, выше оператора цикла for, перестанет быть доступной внутри оператора цикла и во всех вложенных в него блоках. Об этом нам также сообщит компилятор в виде предупреждения:

Рис. 7. Предупреждение компилятора о перекрытии значения переменных.
Рис. 7. Предупреждение компилятора о перекрытии значения переменных.

Но при этом, данный код будет вполне работоспособным. Давайте проверим, что будет выведено на экран при его выполнении:

Рис. 8. Результат выполнения программы.
Рис. 8. Результат выполнения программы.

Как видно из результата выполнения данного кода, значение переменной, объявленной до определения оператора цикла не было изменено. Но в тоже время, получить доступ к значению этой переменной не представляется возможным.

Но что делать, если нам потребуется такая переменная, значение которой будет доступно на всем протяжении программы? Как быть с определенными пользователями настройками для нашего советника?

Глобальные переменные

В этом случае нам необходимы глобальные переменные.

Глобальными они называются отчасти из-за того, что для них выделяется память в глобальном пуле данных, время жизни которого соответствует времени жизни программы. Другими словами, уничтожение глобальных переменных происходит только в момент закрытия программы (ну, или в случае аварийного завершения ее работы).

Объявление глобальных переменных ничем не отличается от объявления локальных, за исключением места их объявления. Если локальные переменные объявляются внутри функций и операторов программы, то глобальные переменные объявляются вне этих блоков.

Так как область видимости глобальных переменных (также как и локальных) начинается с момента их объявления, то глобальные переменные объявляются, как правило, в самом начале программы — до объявления всех служебных и пользовательских функций.

Входные параметры эксперта

Существует еще один вид переменных в программах, написанных на языке программирования MQL. Это, по сути, вид глобальных переменных, предназначенных для хранения пользовательских настроек, которые наш советник будет использовать в процессе своей работы.

Рис. 9. Список входных параметров советника.
Рис. 9. Список входных параметров советника.

Данный тип переменных характерен тем, что по сути, они являются константами, значение которых внутри программы изменить невозможно. Значение данных глобальных переменных указывает пользователь в тот момент, когда устанавливает советника на график:

Рис. 10. Список входных параметров советника.
Рис. 10. Список входных параметров советника.

Значения данных переменных устанавливаются один раз при установке советника на соответствующей вкладке "Входные параметры" в окне свойств эксперта.

Если, по какой-либо причине, нам требуется иметь переменные, значения которых устанавливает пользователь нашего советника, но имеем возможность переопределить их значение в программе, то вместо ключевого слова input следует использовать ключевое слово extern.

Рис. 11. Объявление входных параметров советника.
Рис. 11. Объявление входных параметров советника.

Заключение

В данной статье мы познакомились с такими понятиями, как время жизни (или область видимости) переменных, научились объявлять входные параметры советника, узнали о глобальных и локальных переменных.