丢了的玩具-从UndefVarError说起
相信很多人遇到过著名的UndefVarError:变量未定义
9成情况下,肇事者写了这样一个程序,引起了Julia不满
#Scoping
a=1
for i =1:20
a+=1
end
人家抱怨
UndefVarError: a not defined
in top-level scope at base\none
in top-level scope at Scoping.jl:4
这是因为在一个for loop(循环)里面,所有变量默认为局部变量。你可以想象成整个程序有一个大盒子,而for-end是大盒子里面的一个小盒子,盒子里面有一些玩具。
在玩玩具的时候,程序想找a,然而他(应该说她或者它,不管了,代指Julia1.0以及以后的版本)默认先从这个for-end的小盒子里找。然而小盒子里并没有a,于是崩溃了。
于是,我们有两种办法:
第一种:在全局变量里找a
global a
a=1
for i = 1:20
global a+=1
end
a
非常的happy,但是,如果我只有一个玩具,为啥要用两个盒子?
第二种 建立 let block
let
a=1
for i = 1:20
a+=1
end
a
end
那么我干脆两个盒子都不管,反正我有个大大盒子,在里面找a,总是没错的吧。
Scope的global,local不影响读取,
请看这样一个涉及global,local双层循环
x=1
for i = 1:10
a=i^2
println("a="*string(a))
for j = 1:10
println(i+j+a)
println(x)
end
end
这是可以运行的
被滥用的let-end
于是本性暴露了,所有东西放在一个let-end里,不就完事大吉了吗?
不会,并不会。在Julia语言的设计中,let-end 并不能打穿所有盒子。事实上,众人已经在GitHub上干过架了。
附上连接,不建议围观。。。
https://github.com/JuliaLang/julia/issues/423
我们回到盒子和玩具的问题上来。玩具为什么最好分类放?
为什么呢?这样找的范围小,找的比较快(也许吧),不用担心把所有东西都翻乱了。
如果你在局部有个变量设置成了和全局一样的名字,而它在局部又有和全局不同的用途,那么这种分离是必要的。
对比一下两个loop,上面的是直接在全局操作。
a=1
for i = 1:10
global a = 1
global a = a+i
show(a)
end
a
a=1
for i = 1:10
local a = 1
local a = a+i
show(a)
end
a
这样我本来想输出一组数字,全局的a该干啥去干啥去,然而global不管三七二十一,把a给改了,这在小的地方也许没什么,但在过程很长或很复杂的数值计算里,造成的损失也许是致命的。
Scoping的种类以及控制
全局对应global scope
function对应hard scope
for,while等loop对应soft scope
soft scope 可以用global,local 来加以区分扔出去的东西和循环内部自己的东西
function 可以用module管理(不过如果你的程序不涉及太多函数的话没什么必要),每个module 要用import来加载
函数无global
函数可以有返回值,但通常不能在你看不见的情况下动函数外的东西(Julia不是R!)。
一个好消息是,函数里的循环并不会再加分层
function f(x)
for i in 1:3
x=x^2
end
return x
end
f(2)
···
256
···
using 和 import的一些区别
这个建议弄module的时候弄不迟。。。
常见错误
1.在多层循环里用global之前不先放一个global变量在global上
for i in 1:10
for j in 1:10
global a =i*j
end
if i*j>1
show(1)
end
end
看着办吧,一般都是因为玩的太浪了出的错