Почему я получаю ошибку, когда я «запускаю все», но не при запуске каждой строки по отдельности?

#julia

Вопрос:

Я использую Julia 1.6.2 и Juno, и у меня есть этот код:

 println("0.5772156649015328606065120900824024310421")
jmax = 1000000
gamma = 0
j = 1

for j = jmax:-1:1
    gamma = gamma   1.e0/j
end
gamma = gamma - log(jmax)
println("$gamma, reverse order sum $(jmax)")
 

Ошибки нет, когда я запускаю каждую строку по порядку с помощью Ctrl Enter.
Но у меня есть ошибка, и я получаю следующее сообщение, когда я делаю «выполнить все» (Ctrl Shift Enter).

Предупреждение: Присвоение «гамма» в мягкой области неоднозначно, поскольку существует глобальная переменная с тем же именем: «гамма» будет рассматриваться как новая локальная. Устраните неоднозначность, используя «локальную гамму» для подавления этого предупреждения или «глобальную гамму» для присвоения существующей глобальной переменной.

ОШИБКА: Ошибка загрузки: ошибка UndefVarError: гамма не определена

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

Комментарии:

1. docs.julialang.org/en/v1/manual/variables-and-scoping/. … Похоже, что Юнона, когда вы делаете «запустить все», запускает скрипт в неинтерактивном режиме. В общем, я рекомендую вам переключиться на VS Code, так как в настоящее время это рекомендуемая среда разработки для Julia.

2. VS-код имеет такое же поведение. Идея заключается в том, что запуск файла построчно (или блок за блоком) работает так же, как и REPL, но запуск файла в целом эквивалентен include его запуску.

3. Да, я не хотел подразумевать, что VS — код будет вести себя по-другому, просто Юнона не получает такого внимания к обслуживанию, как VS-код.

Ответ №1:

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

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

В построчном режиме переменная gamma , на которую вы ссылаетесь в цикле for, считается глобальной переменной, которую вы уже определили, и все в порядке.

Однако в режиме выполнения «всего сценария» требуется, чтобы вы явно указали «Я имею в виду глобальную переменную gamma «, так как это соединение не выполняется автоматически.

Итак, в вашем случае просто измените строку внутри цикла for в:

 global gamma = gamma   1.e0/j
 

чтобы явно указать, что вы хотите работать с глобальным gamma , а не с возможным (несуществующим) локальным. Это позволит ему работать как в построчном, так и в файловом режиме.

Комментарии:

1. Я знаю, что здесь нет простого решения, и понимаю, какая сложная история потребовалась, чтобы попасть сюда… но это все равно похоже на уродливую бородавку, которой я бы хотел, чтобы у Джулии не было.

Ответ №2:

Расширяя ответ выше:

Вы должны обернуть свой код в функцию.

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

Кроме того, в функции Джулия может выводить типы, поэтому вычисление выполняется намного быстрее (может быть в 100 раз).

 fuction do_stuff()
    jmax = 1000000
    gamma = 0.0 # define it as a float for type stability!
    j = 1
    
    for j = jmax:-1:1
        gamma = gamma   1.e0/j
    end
    gamma = gamma - log(jmax)
    println("$gamma, reverse order sum $(jmax)")
end
do_stuff()
 

Правила определения области видимости переменных поначалу кажутся неинтуитивными, но для них есть веские причины, и они подробно описаны в руководстве Julia.