Solidity中的存储区——Memory和Storage的爱恨情仇

时间:2024-04-02 16:28:38

——上一篇文章中,我们提到了 值类型引用类型 的概念,现在来看看他们在内存中是如何被分配和互相使用的。


——首先,我们要理解存储区分配的几个原则,对于Solidity编码过程来讲,变量的存储位置(memory和storage存储区)的正确指定非常重要,因为不同数据位置变量赋值产生的结果也不同。

        -在memory和storage之间,以及它们和状态变量(即便从另一个状态变量)中相互赋值,总是会创建一个完全不相关的数据拷贝

        -将一个storage的状态变量,赋值给一个storage的局部变量,是通过引用传递。所以对于局部变量的修改,同时修改关联的状态变量。另一方面,将一个memory的引用类型赋值给另一个memory的引用,不会创建另一个新的拷贝。


——不同数据类型的变量会有各自默认的存储位置,我们再来回顾一下:

         -状态变量总是会存储在storage 中

        -函数参数和返回值默认存放在 内存memory 中

        -结构、数组或映射类型的局部变量,默认会放在 存储storage 中

        -除结构、数组及映射类型之外的简单局部值变量,会储存在栈中        

——下面我们来看几个实际的代码块案例

        -案例一:memory赋值给局部变量

        Solidity中的存储区——Memory和Storage的爱恨情仇

        
        在上述示例中,我们尝试将一个参数s赋值给一个局部变量tmp。可以看到报错信息为Error: Type struct memory is not implicitly convertible to expected type storage pointer。
        从报错可以看出,默认的的参数是memory类型的,而局部变量tmp由于是引用类型(struct)的值,所以默认是存在storage中的。由于在区块链中,storage必须是静态分配存储空间的。而由参数传递进来的值仅仅是一个storage类型的指针。如果进行这样的赋值,就必须制定tmp存储空间为memory。


        -案例二: storage转storage

        Solidity中的存储区——Memory和Storage的爱恨情仇

        

当我们把一个storage类型的变量赋值给另一个storage时,我们只是修改了它的指针。在上面的代码中,我们将传入的storage变量,赋值给另一个临时的storage类型的tmp时,并修改tmp.a = "Test",最后我们会发现合约的状态变量s也被修改了。

        -案例三:memory赋值给状态变量

       Solidity中的存储区——Memory和Storage的爱恨情仇    

        将一个memory类型的变量赋值给一个状态变量时,实际是将内存变量拷贝到存储中。在方法中,我们把tmp赋值给s后,再修改tmp值,并不能产生任何变化。赋值时,完成了值的拷贝,后续他们不再有任何的关系。

        -案例四:storage转为memory

        Solidity中的存储区——Memory和Storage的爱恨情仇

        将storage类型的值转为memory,实际是将数据从storage中拷贝到memory中。在上面的例子中,我们看到,拷贝后对tmp变量的修改,完全不会影响到原来的storage变量。

        -案例五:memory转为memory

        Solidity中的存储区——Memory和Storage的爱恨情仇

        memory之间的复杂类型的相互赋值实际上是引用的传递,并不会拷贝数据。在上面的代码中,memoryToMemory()传递进来了一个memory类型的变量,在函数内将之赋值给tmp,修改tmp的值,发现外部的memory也被改为了other memory。

        

——以上就是Solidity中常见的几种存储转换,供参考使用