Области видимости переменных
Материал этой главы не сразу укладывается в голове, потому что правила областей видимости, хоть и интуитивны, но не так просты. Советую попрактиковаться с областями видимости.
Существует три типа областей видимости переменных: глобальная, мягкая локальная и жесткая локальная.
Глобальная область видимости
В отличие от многих языков программирования, в Julia не существует одной общей области видимости на всю программу. Причины такого решения очевидны: опыт предыдущих языков показал, что глобальные, в глобальном смысле, переменные - это зло. Любое определение должно иметь четкую адресацию в пространстве имен и принадлежать определенному модулю. Поэтому, то, что в Julia называется глобальной областью, не распространяется дальше модуля. Интерактивная среда REPL вводит свою глобальную область: модуль Main
. Таким образом, все, что вы объявляете в REPL, принадлежит модулю Main
. Это можно увидеть:
julia> f(x)=x+1
f (generic function with 1 method)
julia> which(:f)
Main
Переменные, объявленные на верхнем уровне REPL, будут глобальными, принадлежащими Main
. Если вы напишете программу, поместив код в файле вне всякого модуля - этот код будет принадлежать тоже Main
. Любая переменная верхнего уровня любого модуля будет глобальной переменной (этого модуля).
Локальная область видимости
Julia использует модель лексических областей, а не динамических. Лексическая родительская область окружает функцию или структуру в момент определения. Не надо путать ее с динамической родительскую областью видимости (областью вызывающего кода).
Локальная область видимости разделяется на жесткую и мягкую. Есть у них общие свойства. У них нет своего квалификатора имени, как у модуля. Переменная введенная в локальной области не переходит потом в родительскую область видимости, однако переменные из родительской области могут быть унаследованы локальной областью. Локальные области могут быть вложенными.
Ключевые слова local
и global
, поставленные перед переменной в локальной области, позволяют явно указать, к какой области будет относиться переменная.
Жесткая локальная область видимости
Теперь зайдем с другого конца. Любая функция, должна гарантировать одинаковое поведение вне зависимости от окружения, существующего в момент ее выполнения, динамической. Это тоже очевидно, иначе мы бы не смогли безопасно вызывать любую функцию в нашем коде: "А вдруг она внутри использует переменные с теми же именами, что у нас уже определены?" С этим тоже согласятся программисты на любом языке. Тоже самое касается анонимных функций.
Разумно под это строгое правило так же подвести любую изменяемую или неизменяемую структуру, имеющую собственные поля (если бы в Julia существовали классы в терминах ООП, то они тоже попали бы сюда).
Итого, любая функция, в том числе, анонимная функция, в том числе do
-блок, а так же структура (struct
) вводит такую само собой разумеющуюся для любого программиста форму области видимости, называемую в Julia жесткой областью видимости.
Функции и структуры в момент их определения могут наследовать (замыкать) переменные из родительской глобальной области видимости за исключением, когда существует попытка изменить переменную из глобальной области или переменная явно помечена как local
. Иными словами, по умолчанию жесткая область видимости унаследует из лексической глобальной области переменные только для чтения. Это согласуется с тем, что , например, нужно иметь возможность создавать замыкания. Ключевое слово global
разрешит доступ для записи глобальной переменной. Таким образом, случайно изменить глобальную переменную из функции программист не сможет.
Интересно, что в случае объявления вложенных функций (одна объявлена в теле другой) область действия внешней по отношению к внутренней является родительской, но не глобальной. При этом внутренняя функция наследует все переменные из внешней как для чтения, так и для записи.
Мягкая локальная область видимости
Мягкая локальная область - это циклы for
, while
, списковые включения (синтаксис создающий генераторы и другие итераторы с помощью круглых или квадратных скобок), блоки try-catch-finally
и let
.
В мягкой области видимости все переменные родительской области, за исключением помеченных словом local
наследуются для чтения и записи. Это тоже логично, так как, чаще всего код в циклах и упомянутых выше блоках манипулирует определенными в родительской области переменными.
Ключевое слово local
заставляет переменную быть строго локальной.
Блоки if и begin
Они, вообще, не вводят никакую область видимости.