值域,变量的作用域。
是变量有效区域,每一种高级语言,都会对变量作用域做出定义,以规范变量命名规则,避免变量命名引起的冲突。
作用域是变量有效的代码区域,变量有效性限制在这些代码块内部。但可以通过特定的语法,变量值在代码块中传递。
先找一下感觉:
julia> module test
x = "inside"
foo() = println("x in module test: ",x)
end
Main.test
julia> x = "outside"
"outside"
julia> import .test
julia> test.foo()
x in module test: inside
julia> x
"outside"
上面的例子里,有两个x变量,module test的外面和里面各一个。
全局作用域(Global Scope)
定义在所有函数外部的变量,可以在程序的任何地方访问。
😎可以访问不是任意访问,具体使用规则见下面的实例:
julia> module A
a = "A.a" #定义并赋值global变量A.a
end
Main.A
julia> module B
module C
c = "C.c"
end
b = C.c #可以直接使用下级module C下的global类型变量C.c
import ..A #引入激活module A
bb = A.a #激活module A后,可以使用 A.a的值
end
Main.B
julia> module D
d = a #没有引入module A,所以global类型的A.a不可见,此处a作为D.a看待,在module D中,D.a没有被定义
end
ERROR: UndefVarError: a not defined
julia> module D
d = A.a #没有引入module A,所以module A不可见
end
WARNING: replacing module D.
ERROR: UndefVarError: A not defined
julia> module E
import ..A #引入激活module A
A.a = "E.a" #A.a不能在module E下重新赋值
end
ERROR: cannot assign variables in other modules
本地作用域(Local Scope)
本地作用域继承父本地作用域中的所有变量,用于读取和写入。
本地作用域继承在其父全局作用域中分配的所有全局变量(如果它被全局的if或begin块包围)。
局部作用域不是名称空间,不能访问从父作用域中的变量。
这是本地(for)作用域下变量不能在外部访问的实例,对于模块内默认的global变量,可以通过”模块名.变量名“来引用,但是对于本地类型的代码块中的变量,却不提供这样的机会:
julia> for i = 1:1
x = "in for"
println(x)
end
in for
julia> x
ERROR: UndefVarError: x not defined
如果希望本地类型的代码块中的变量被外部使用,可以强制做global声明,这样写:
julia> for i = 1:1
global x = "in for"
end
julia> x
"in for"
在本地范围内,所有变量都可以从其父全局范围块继承,除非:
本地范围内同名变量被赋值,生成新的同名local类型变量,这样在本地范围内看到的同名变量只能是这个local类型的。
换句话说,父全局块内的全局变量,在本地块内,可读不可写。下面的实例展示了这样的效果:
julia> x,y = "outside x","outside y"
("outside x", "outside y")
julia> function foo()
x = "inside x"
return join([x,y],"+")
end
foo (generic function with 1 method)
julia> foo()
"inside x+outside y"
julia> x
"outside x"
嵌套函数可以修改其父作用域的本地变量,注意是本地变量,并没有违反全局变量在本地的可读不可写的原则。
😎回看本章节的起始部分,这在全局的module中,是不被允许的。
julia> x,y = "outside x","outside y"
("outside x", "outside y")
julia> function f1()
x = "inside f1 x"
function f2()
x = "inside f2 x" #f1下被赋值的x在这里被重新赋值
return join([x,y],"+")
end
return join([f2(),x],"+") #f1包括f2,只有一个local的x
end
f1 (generic function with 1 method)
julia> f1()
"inside f2 x+outside y+inside f2 x"
julia> x,y
("outside x", "outside y")
函数调用函数不看做是嵌套,不可以修改被调用函数其作用域的本地变量,这个和前面的嵌套函数不一样,观察下面的实例:
julia> x,y = "outside x","outside y"
("outside x", "outside y")
julia> function f1()
x = "inside f1 x"
return join([x,y],"+")
end
f1 (generic function with 1 method)
julia> function f2()
x = "inside f2 x"
return join([f1(),x],"+")
end
f2 (generic function with 1 method)
julia> f1()
"inside f1 x+outside y"
julia> f2()
"inside f1 x+outside y+inside f2 x"
一个函数可以调用事先没用定义的函数,这确实和我们先声明再使用的习惯相悖,但有时也能提供方便。下面我们把判断奇偶的iseven()和isodd()重新包装一下,看看这种函数调用的形式(传说中的递归):
julia> even(n) = iseven(n) ? true : odd(n-1)
even (generic function with 2 methods)
julia> odd(n) = isodd(n) ? true : iseven(n-1)
odd (generic function with 2 methods)
julia> even(1)
false
julia> even(2)
true
julia> odd(1)
true
julia> odd(2)
false
begin块
从我们实际的实验看,begin并没有自己的值域,我们先看嵌套的情况:
julia> begin local x =1
begin local x = 2
end
end
2
再看外部变量在 begin块里被引用的情况:
julia> x = "aaa"
"aaa"
julia> begin println(x)
end
aaa
再看begin块内部声明的变量在外部被引用的情况:
julia> y = "yyy"
end
"yyy"
julia> y
"yyy"
😎这样看来,变量穿过“begin”标记没有什么限制。
let块
从我们实际的实验看,let块内申明的变量会开辟local的存储空间,可以简单地理解成,在let块内赋值或者声明的变量,都只在let块内生效,下面我们看实例:
julia> x,y,z = "outside x","outside y","outside z"
("outside x", "outside y", "outside z")
julia> let x = "inside x",z
println(x)
println(y)
println(z)
end
inside x
outside y
ERROR: UndefVarError: z not defined
😎let块内的变量z,因为被重新声明但没有被赋值,因此报错。
紧接上面命令行,执行以下命令,可以看到,跳出let块后,原先被赋值的x,y,z变量,依旧没有变,let块内的变量作用域只被限定在let块内。
julia> x
"outside x"
julia> y
"outside y"
julia> z
"outside z"
由于let块内申明的变量重新开辟local存储空间的特性,出现了“i = i”的奇特现象(右边的i是let块外面的,左边的i是let里自己的):
julia> i = 1;
julia> while i <= 2
let i = i * 10 # 左i非右i
println("i in the let block : ",i)
end
global i += 1
println("i in the while block : ",i)
end
i in the let block : 10
i in the while block : 2
i in the let block : 20
i in the while block : 3
for循环
我们可以把for块看作是封闭的,即使同名,for内也看不到外面的变量,例如:
julia> function f_for()
i = 0
for i = 7:9
println("inside for i: ",i)
end
println("outide for i: ",i)
end
f_for (generic function with 1 method)
julia> f_for()
inside for i: 7
inside for i: 8
inside for i: 9
outide for i: 0
😎有时,在循环体内使用外部变量是必须的,所以Jullia提供了关键字outer,作为语法的补充:
julia> function f_for()
i = 0
for outer i = 7:9
println("inside for i: ",i)
end
println("outide for i: ",i)
end
f_for (generic function with 1 method)
julia> f_for()
inside for i: 7
inside for i: 8
inside for i: 9
outide for i: 9
网友评论