Lua中未显式赋值时ref表索引值为何自动变更?
Lua 5.4表赋值导致原表意外修改的问题
在Lua 5.4中,将ref表赋值给tab[c]后,修改tab[c]的元素时,原ref表的内容也会被改变。原本预期tab[c] = ref是创建ref表的副本,但实际所有tab[c]都指向同一个ref表,导致修改操作影响了原表。
复现代码
-- Lua v5.4 local tab = {} local ref = {"car1","%line2%","door3"} local str = {{"%%line2%%","line"},{"car1","car"}} for c=1,3 do tab[c] = ref print("\n----block "..c) print("\n--ref table ") for h=1,#ref do print("ref"..c,ref[h]) end print("\n--replacement") for d=1,#tab[c] do for i=1,#ref do if string.match(tab[c][d],str[1][2]) then local repl =string.gsub(tab[c][d],str[1][1],"asdf") tab[c][d] = repl print("tab"..c.."-"..d,tab[c][d]) end end end print("\n--check") for h=1,#tab[c] do print("check tab"..c.."-"..h,tab[c][h]) end end
运行结果
----block 1 --ref table ref1 car1 ref1 %line2% ref1 door3 --replacement tab1-2 asdf --check check tab1-1 car1 check tab1-2 asdf check tab1-3 door3 ----block 2 --ref table ref2 car1 ref2 asdf ref2 door3 --replacement --check check tab2-1 car1 check tab2-2 asdf check tab2-3 door3 ----block 3 --ref table ref3 car1 ref3 asdf ref3 door3 --replacement --check check tab3-1 car1 check tab3-2 asdf check tab3-3 door3 [Finished in 27ms]
问题原因
Lua中的表是引用类型,当执行tab[c] = ref时,并没有复制ref表的内容,只是把ref表的引用地址赋值给了tab[c]。这意味着所有tab[1]、tab[2]、tab[3]都指向同一个内存地址中的ref表,修改其中任意一个子表的元素,都会直接修改原ref表的内容。
解决方案
要实现创建ref表的副本,需要手动编写一个表复制函数,在每次循环时复制ref的所有元素到新表中,再将新表赋值给tab[c]。
修改后的代码
-- Lua v5.4 local tab = {} local ref = {"car1","%line2%","door3"} local str = {{"%%line2%%","line"},{"car1","car"}} -- 表复制函数,复制一维数组表 local function copy_table(src) local dst = {} for i, v in ipairs(src) do dst[i] = v end return dst end for c=1,3 do tab[c] = copy_table(ref) -- 复制ref表的内容到新表 print("\n----block "..c) print("\n--ref table ") for h=1,#ref do print("ref"..c,ref[h]) end print("\n--replacement") for d=1,#tab[c] do for i=1,#ref do if string.match(tab[c][d],str[1][2]) then local repl =string.gsub(tab[c][d],str[1][1],"asdf") tab[c][d] = repl print("tab"..c.."-"..d,tab[c][d]) end end end print("\n--check") for h=1,#tab[c] do print("check tab"..c.."-"..h,tab[c][h]) end end
修改后运行结果
----block 1 --ref table ref1 car1 ref1 %line2% ref1 door3 --replacement tab1-2 asdf --check check tab1-1 car1 check tab1-2 asdf check tab1-3 door3 ----block 2 --ref table ref2 car1 ref2 %line2% ref2 door3 --replacement tab2-2 asdf --check check tab2-1 car1 check tab2-2 asdf check tab2-3 door3 ----block 3 --ref table ref3 car1 ref3 %line2% ref3 door3 --replacement tab3-2 asdf --check check tab3-1 car1 check tab3-2 asdf check tab3-3 door3 [Finished in 26ms]
可以看到,修改后的代码中,原ref表的内容始终保持不变,每个tab[c]都是独立的副本,修改操作不会互相影响。
内容的提问来源于stack exchange,提问作者Jepamb
相关产品推荐
相关产品推荐

