julia变量作用域的问题

在提问之前请确定你已经努力阅读了文档,并且尝试自己在互联网上搜索。

请尽可能提供你的demo代码或者GitHub的gist地址。

# code

SS=200
println("函数前的SS=== $SS")

for i in 1:5
println("这是第 $i 次循环")
AA1=200
function  add( AA,B)
 
       SS=AA+B

    return SS
end
SS=add(AA1,20)
#println("这时候的SS=== $SS")
dd=add(20,30)
#println("cc==== $cc")
println("函数后的SS $SS")
println("dd==== $dd")

end

这是一个示例代码,我发现当Julia的函数定义在循环内部的时候,第二次调用add函数,会改变第一次调用add函数返回的SS值,我可以解决这个问题,但是不理解为什么会这样,函数内部的返回值SS,如何影响到了函数外部的值?我的juli版本是1.10.4

Scope of Variables · The Julia Language

这是楼主提供的函数的执行结果,第二次调用add函数的时候SS的值并没有改变。

函数前的SS=== 200
这是第 1 次循环
函数后的SS 220
dd==== 50
这是第 2 次循环
函数后的SS 220
dd==== 50
这是第 3 次循环
函数后的SS 220
dd==== 50
这是第 4 次循环
函数后的SS 220
dd==== 50
这是第 5 次循环
函数后的SS 220
dd==== 50

测试环境为vscode + julia v1.10.4
另外参考试写一个Julia Scoping作用域的中文讲解


这太奇怪了!这个截图是在我的电脑运行的结果。不明白为什么会不同?
不知道您是否把函数放到for循环外了,我知道把add函数定义放到for循环外,会是您发的这个结果,但是我不太理解,为什么函数定义放到for循环内就是这样子了?看起来是函数定义内的局部变量SS,覆盖了for循环内的局部变量SS,我想应该是这个原因。但是在我看来,函数内的变量SS只局限在函数定义内,不应该影响到for循环内的SS,这是为什么呢?


我发现了,您是在julia的REPL运行的代码对吗?确实是这个结果。但是当我用vscode+julia运行这个脚本的时候,就会出现这个问题!!!
更迷惑了,不明白这是为什么?
在vscode中,我使用的是Run Code,或者使用vscode for julia也是一样,SS都会是50,但是当我直接粘贴在julia的REPL中,运行结果就是您发的了,这太奇怪了!
我不明白这里的差别在哪里,我猜,可能直接运行脚本和REPL模式的变量作用域有所不同?

原因在你发的这张图里已经说得很清楚了,代码块嵌套时内部代码块可以访问上级作用域。

在REPL中,嵌套函数中的内部函数可以访问上级作用域。看了下面这个例子你就明白了。嵌套函数中的内部函数默认使用的是global变量,这个global不能访问全局作用域,但能访问上级作用域,即外层函数内的变量。

## Case 1
function outer(a)
    function inner()
        a = 100 # 等价于global a = 100
    end
    println("调用inner函数前a=$a") # 输出: 调用inner函数前a=10
    inner()
    println("调用inner函数后a=$a") # 输出: 调用inner函数后a=100
end
outer(10)
## Case 2
function outer(a)
    function inner()
        local a = 100
    end
    println("调用inner函数前a=$a") # 输出: 调用inner函数前a=10
    inner()
    println("调用inner函数后a=$a") # 输出: 调用inner函数后a=10
end
outer(10)

根据刚才的测试,我想在REPL中用for代码块包裹的内部函数不能访问上级作用域。

SS = 200
println("函数前的SS=== $SS")
for i in 1:5
    AA1 = 200
    function add(AA, B)
        SS = AA + B # 默认行为 local SS = AA + B
        return SS
    end
    SS = add(AA1, 20)
    dd = add(20, 30)
    println("函数后的SS $SS")
    println("dd==== $dd")
end

但在你提供的终端里面执行的时候SS = AA + B 的默认行为是global SS = AA + B,并且伴随一条警告。总之,现在你可以通过明确使用global SS = AA + B或者local SS = AA + B来达到想要的目的,无论在终端还是REPL执行。

明白了!!!
非常感谢您的回答! :+1:
另外推荐这个网址:https://www.math.pku.edu.cn/teachers/lidf/docs/Julia/html/_book/index.html
李东风老师写的julia入门,第八章关于作用域的内容特别详细,也包括嵌套函数定义域内容。如果有人看到这个问题,可以借鉴下