1.10 Переменные: локальные, формальные, статические, глобальные, Extern, Input

Доброго времени суток. В одном из первых уроков мы рассмотрели возможные Типы данных в языке программирования MQL. Уяснили, что переменные должны быть обязательно объявлены под соответствующем типом данных. Теперь пришло время рассмотреть, какие переменные бывают и чем отличаются друг от друга.

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

Это тип переменной, которая объявлена внутри конкретной функции, т.е. на локальном уровне. Такая переменная может существовать только внутри заданной функции.

Область видимости это тот участок программы, в котором разрешено ссылаться на эту переменную. Пример:

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

То же самое касается и переменных Var2 и Var3. Первая может существовать только в функции FirstFunction, вторая в SecondFunction. После того, как функция завершила свою работу — переменная стирается из памяти.

Пример внутри одной функции:

Переменная целого типа a была объявлена внутри самой функции OnStart, тогда как переменная b объявлена внутри условного оператора if. Соответственно после оператора if переменная a останется существовать, тогда как переменная b сотрется из памяти после закрытой фигурной скобки оператора и ее уже нельзя будет использовать.

Еще один похожий пример:

Тут переменная b1 существует только в пределах оператора цикла for и может использовать в условном операторе if, от открытой до закрытой фигурной скобки. Переменная c1 существует только в условном операторе if, но может учитывать в расчете как переменную a1, так и b1.

Формальные переменные

Формальными называются переменные, которые указываются в свойствах функции и могут быть использованы только в ее области видимости.

Передаваемые в функцию Function переменные Order_Ticket и Order_Time являются локальными, но в теле самой функции они принимают значение ticket и time, и являются формальными.

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

При попытке изменения переменной целого типа а компилятор будет ругаться на ошибку. Но переменную d можно изменять внутри тела функции.

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

В функцию OtherFunction были переданы только локальные переменные One и Two, соответственно код учтет и выдаст принт их значений 5 и 6. Так как значение Three не было передано, то значение формальной переменной A3 становится равной 10. Пропускать передаваемые значения можно только, если у формальной переменной есть константа. Стоит заметить, что формальная переменная A2 тоже инициализирована константой, но т.к. ей передано значение с локального уровня, то значение 2.0 тут не учитывается.

Значения в функции читаются слева направо, и если мы зададим формальной переменной A2 константу, то все переменные, следующие за ней тоже обязаны иметь какое-либо значение по умолчанию, иначе такой код будет невозможно скомпилировать.

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

Статические переменные

Статическая переменная отличается от локальной тем, что ее значение сохраняется в функции с момента ее объявления до выгрузки программы. Может быть проинициализирована только константой или константным выражением, соответствующем ее типу, т.е. ее значением нельзя указать функцию или любое выражение. Чтобы ее задать, нужно перед типом данных переменной поставить слово static:

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

В примере выше в функции Func мы задали статическую переменную. Далее прибавили к ее нулевому значению единицу и вывели принт. В функции обработки событий OnStart через цикл for четыре раза обратились к этой функции. Соответственно запись в журнале по очереди выдаст нам результат: 1,2,3 и 4, а не четыре раза по единице, как это бы было с локальной функцией.

Применений ей можно придумать много, самый простой это сравнивать в советнике значение цены Bid на предыдущем тике с текущим значением, а после переписывать статическую переменную под новые данные:

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

Данный тип переменных объявляется вне функции, на том же уровне, что и свойства программы, include и импорт. Они не являются локальными и их можно использовать в любой части кода, в любой функции, т.е. их областью видимости является вся программа. Как правило, их следует объявлять перед всеми функциями, рядом с #property свойствами программы.

Если переменная не инициализирована программистом, то по умолчанию она равна нулю. Проинициализировать ее можно только соответствующей константой или константным выражением. Инициализация происходит однократно, т.е. уже присвоенное имя глобальной переменной нельзя передавать новым переменным внутри какой-либо функции. Время ее жизни определено началом ее объявления и окончанием работы программного кода.

Как видите, через сообщение в журнал мы смогли без труда получить значение Global в каждой из функций.

Небольшой лайфхак: Если в принте вначале прописать слово __FUNCTION__, то оно выведет в журнал наименование той функции, в которой был запущен этот принт. Это очень помогает искать ошибки в разных частях кода, а также визуально отделять разные информационные сообщения друг от друга.

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

Extern переменные

Тип переменных Extern отличается от глобальных тем, что они являются внешними. Это именно те переменные, которые пользователь видит в настройках программы в окне «Входные параметры«:

Они нужны для точной настройки скрипта, советника или индикатора. Внешние переменные не могут быть проинициализированы функцией или массивом, и должны соответствовать своему типу данных. Длина string переменной не может быть больше 63 символа. Объявляются они на глобальном уровне вне функции в самом верху кода. Для этого перед типом данных нужно добавить слово extern (внешний):

Чтобы эти переменные были видимы в скрипте, нужно прописать свойство программы #property script_show_inputs. В советниках и индикаторах этого делать не нужно, они видимы по умолчанию. Теперь эти четыре переменные будут иметь следующий вид в настройках программы:


Для отображения собственного имени переменной, которое более удобно для чтения пользователем, используется знак комментария // после нее. Т.е. программный код будет обращаться к объявленному имени этой переменной, но во входных параметрах вашего кода будет виден более читаемый текст. Чтобы достичь такого эффекта, нужно указать в свойствах строгий режим компиляции strict.

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

Переменную типа extern можно изменять в любом месте программного кода:

Input переменные

Единственное и основное отличие переменной типа input от extern в том, что ее значение нельзя менять в программном коде после объявления.

В обоих внешних переменные предусмотрено использовать ENUM тип данных, который позволяет сделать выбор из списка. Это может быть таймфрейм индикатора, его метод, цена закрытия и т.п.

Проверьте этот код для большего понимания в окне настроек скрипта, там появится три списка с выбором. Вместо объявления определенного типа данных для переменных, были использованы уже предопределенные значения ENUM терминала. Таких значений огромное множество, в основном они используются для работы с индикаторами.

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

Если же пользователь хочет создать свой собственный ENUM список, тогда его необходимо объявить перед внешними переменными. Попробуем сделать список из трех значений:

Вначале пишется слово enum, далее его наименование (в нашем случае это MyList) и уже в фигурных скобках указывается столько параметров, сколько нам нужно. Мы взяли три и присвоили им значения 1, 2 и 3. Между параметрами ставится запятая, у последнего параметра не нужно ставить никакой знак. У енумов значения могут быть только целыми числами. После этого через input и extern мы вызываем получившийся енум, задаем его переменной какое-либо имя (list) и значение по умолчанию.

У переменных енум тоже можно задавать пользовательский текст через комментарий для отображения их в настройках окна:

Sinput переменные

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

Получается, что у переменных типа sinput значения Старт, Шаг и Стоп автоматически становятся неактивными. Флажки переменных типа string по умолчанию нельзя выбрать для оптимизации, т.к. текст невозможно настроить.

Если вы хотите, чтобы пользователь вашего советника мог оптимизировать только часть настроек — sinput переменные помогут вам с этим.


На этой ноте можно завершить сегодняшний урок. Прикреплять .mq4 для данного урока не вижу смысла, весь пройденный материал для практики вы сможете легко скопировать с этого поста.

0. Начало работы

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Заполните поле
Заполните поле
Пожалуйста, введите корректный адрес email.
Вы должны согласиться с условиями для продолжения

Меню