您的当前位置:首页正文

浅谈lua拷贝

2024-12-01 来源:个人技术集锦

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

以上为个人见解,如果错误欢迎指正。

显示全文