Variables 函数/变量范围(传递值或参考?)
我完全被的变量作用域和函数参数传递(值或引用)搞糊涂了 请参阅下面的代码:Variables 函数/变量范围(传递值或参考?),variables,scope,lua,Variables,Scope,Lua,我完全被的变量作用域和函数参数传递(值或引用)搞糊涂了 请参阅下面的代码: local a = 9 -- since it's define local, should not have func scope local t = {4,6} -- since it's define local, should not have func scope function moda(a) a = 10 -- creates a global var? en
local a = 9 -- since it's define local, should not have func scope
local t = {4,6} -- since it's define local, should not have func scope
function moda(a)
a = 10 -- creates a global var?
end
function modt(t)
t[1] = 7 -- create a global var?
t[2] = 8
end
moda(a)
modt(t)
print(a) -- print 9 (function does not modify the parent variable)
print(t[1]..t[2]) -- print 78 (some how modt is modifying the parent t var)
因此,这种行为完全使我困惑
- 这是否意味着表变量 由传递给函数的 参考而非价值
- 全局变量是如何创建的
与已定义的冲突
局部变量
- 为什么
能够 无法修改表modt
要修改变量的值moda
- 为什么
函数
,表
,用户数据
和线程
(协同程序)类型通过引用传递。其他类型按值传递。或者像一些人喜欢说的那样;所有类型都按值传递,但函数
、表
、用户数据
和线程
都是引用类型
string
也是一种引用类型,但它是不可变的、内部的和写时复制的-它的行为类似于值类型,但性能更好
下面是正在发生的事情:
local a = 9
local t = {4,6}
function moda(a)
a = 10 -- sets 'a', which is a local introduced in the parameter list
end
function modt(t)
t[1] = 7 -- modifies the table referred to by the local 't' introduced in the parameter list
t[2] = 8
end
也许这会让人们了解事物为何会如此:
local a = 9
local t = {4,6}
function moda()
a = 10 -- modifies the upvalue 'a'
end
function modt()
t[1] = 7 -- modifies the table referred to by the upvalue 't'
t[2] = 8
end
-- 'moda' and 'modt' are closures already containing 'a' and 't',
-- so we don't have to pass any parameters to modify those variables
moda()
modt()
print(a) -- now print 10
print(t[1]..t[2]) -- still print 78
您猜对了,表变量是通过引用传递的。引用: Lua中有八种基本类型:nil、boolean、number、string、function、userdata、thread和table。 表、函数、线程和(完整的)userdata值都是对象:变量实际上并不包含这些值,只包含对它们的引用。赋值、参数传递和函数返回总是操纵对这些值的引用;这些操作并不意味着任何类型的复制
所以nil、boolean、数字和字符串都是按值传递的。这正好解释了您观察到的行为。我不会重复Bas Bossink和jA_cOp关于引用类型的回答,但是: --因为它是定义局部的,所以不应该有func作用域 这是不正确的。Lua中的变量是,这意味着它们是在一个代码块及其所有嵌套块中定义的。
local
所做的是创建一个新变量,该变量仅限于语句所在的块,该块是函数体、“缩进级别”或文件
这意味着,无论何时引用变量,Lua都将“向上扫描”,直到找到一个代码块,其中该变量被声明为局部变量,如果没有这样的声明,则默认为全局范围
在这种情况下,a
和t
被声明为局部的,但声明在全局范围内,因此a
和t
是全局的;或者最多是当前文件的本地文件
然后,它们不会在函数内部被重新声明为local
,而是被声明为参数,这具有相同的效果。如果不是函数参数,函数体内部的任何引用仍然会引用外部的变量
在lua-users.org上有一篇文章,其中有一些例子可能比我试图解释的更能帮助你。也是一本好书
这是否意味着表变量通过引用而不是值传递给函数
对
全局变量创建如何与已定义的局部变量冲突
事实并非如此。这可能是因为您有一个名为t
的全局变量,并将其传递给一个名为t
的参数的函数,但这两个t
是不同的。如果将参数重命名为其他名称,例如,q
,则输出将完全相同modt(t)
只能修改全局变量t
,因为您通过引用传递它。例如,如果调用modt({})
,则全局t
将不受影响
为什么modt能够修改表格,而moda却不能修改a变量
因为参数是局部的。将参数命名为
a
类似于使用locala
声明局部变量,不同之处在于参数显然接收传入的值,而常规局部变量不接收。如果您的参数被称为z
(或者根本不存在),那么moda
确实会修改全局ajA_cOp说“所有类型都是按值传递的,但函数、表、用户数据和线程都是引用类型”是正确的
这与“表通过引用传递”之间的区别很重要
在这种情况下没有区别
function modt_1(x)
x.foo = "bar"
end
结果:“通过引用传递表”和“通过值传递表,但表是引用类型”将执行相同的操作:x现在将其foo字段设置为“bar”
但对于这个功能来说,它是一个与众不同的世界
function modt_2(x)
x = {}
end
在这种情况下,通过引用传递将导致参数更改为空表。但是,在“传递值,但它是引用类型”中,新表将在本地绑定到x,并且参数将保持不变。如果您在lua中尝试这一点,您会发现这是第二次发生(值是引用)。这与按引用传递略有不同。(见我的答案)。特别是函数(x)x={}end
的行为是不同的。一切都是按值传递的,某些类型(表、函数、线程和(完整的)用户数据值)是引用。这些引用是按值传递的。我发现一个很好的方法来考虑这一点,就是所有的东西都是按值传递的。然而,碰巧有些类型只是引用。引用本身是通过值传递的,这就是为什么您的示例不改变“t”。很好的解释:)