lua中对象的拷贝分为2种:浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。
简单来说只是对一些基本的类型进行复制,而像table这样的类型则直接引用。目前对于浅拷贝有2种说法:
1.赋值操作符"="即是浅拷贝
2.使用代码实现浅拷贝,代码如下:
function shallow_copy(object)
local newObject
if type(object) == "table" then
newObject = {}
for key, value in pairs(object) do
newObject[key] = value
end
else
newObject = object
end
return newObject
end
对于一些基本的类型(string,number,boolean,nil)来说,浅拷贝出来的对象值的修改不会影响原来对象的值。使用"="和shallow_copy()的效果是一样的。如:
local str1 = "hello world"
local str2 = str1 ==>等效于 local str2 = shallow_copy(str1)
str2 = "hello lua"
print("str1=", str1) -- str1=hello world
print("str2=", str2) -- str2=hello lua
对于table对象来说,使用"="和shallow_copy()的效果是不一样的。如:
local t1 = {s1 = "hello c", s2="hello c++", tt = {num1 = 1, num2 = 2}}
local t2 = shallow_copy(t1)
t2.s1 = "hello lua"
print(t1.s1) -- hello c
local t3 = t1
t3.s1 = "hello lua"
print(t1.s1) -- hello lua
假设对t1中的table对象进行修改会发生什么呢?不妨来试试
t2.tt.num1 = 11
print(t1.tt.num1) -- 11
当对table中的table进行修改原table也是被改变的。这是为什么呢?仔细观察shallow_copy()这个函数就会发现,当要拷贝的对象是table时,会对table进行一次遍历,将对应的值进行"="操作。处于table第一层的基本类型则会被复制,而table则是引用。
深拷贝不仅仅对基本类型进行复制,对于table也会开辟新的内存,进行一一复制(table的table)。深拷贝代码如下:
function deep_copy(object)
local lookup = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup[object] then
return lookup[object]
end
local newObject = {}
lookup[object] = newObject
for key, value in pairs(object) do
newObject[_copy(key)] = _copy(value)
end
return setmetatable(newObject, getmetatable(object))
end
return _copy(object)
end
深拷贝不仅对基本类型进行了复制,对table也会进行递归拷贝。例子如下:
local t1 = {s1 = "hello c", s2="hello c++", tt = {num1 = 1, num2 = 2}}
local t2 = deep_copy(t1)
t2.s1 = "hello lua"
t2.tt.num1 = 11
print(t1.s1) -- hello c
print(t1.tt.num1) -- 1
深拷贝出来的对象的任何操作对原来的对象不会有任何的影响。
其中 setmetatable(newObject, getmetatable(object)) 这个操作是对原table的元表进行操作。
特别说明:有的人可能在网上会看到如下的深拷贝函数
function deep_copy_other(object)
local function _copy(object)
if type(object) ~= "table" then
return object
end
local newObject = {}
for key, value in pairs(object) do
newObject[_copy(key)] = _copy(value)
end
return setmetatable(newObject, getmetatable(object))
end
return _copy(object)
end
对于这2个函数的不同之处可以通过一个例子来说明,如下:
local t = {1, 2, 3}
local t1 = {key1 = t, key2 = t}
local t2 = deep_copy(t1)
local t3 = deep_copy_other(t1)
print("t1.key1==t1.key2:", t1.key1==t1.key2) -- true
print("t2.key1==t2.key2:", t2.key1==t2.key2) -- true
print("t3.key1==t3.key2:", t3.key1==t3.key2) -- false
t1中key1和key2所指向的是同一个table t,所以通过key1去修改t中的值,key2也会相应的改变(指向相同)。由于深拷贝是完全的拷贝副本,对于指向同一个对象的情况在进行深拷贝的应该也遵循这样的关系。deep_copy_other()这个深拷贝函数就不遵循这样的关系,所以说deep_copy_other()这个函数不是一个正确的深拷贝。
如下:
t3.key1[1] = 11
print(t3.key1[1], t3.key2[1]) -- 11 1
以上为个人见解,如果错误欢迎指正。