——上一篇文章中,我们提到了 值类型 和 引用类型 的概念,现在来看看他们在内存中是如何被分配和互相使用的。
——首先,我们要理解存储区分配的几个原则,对于Solidity编码过程来讲,变量的存储位置(memory和storage存储区)的正确指定非常重要,因为不同数据位置变量赋值产生的结果也不同。
-在memory和storage之间,以及它们和状态变量(即便从另一个状态变量)中相互赋值,总是会创建一个完全不相关的数据拷贝
-将一个storage的状态变量,赋值给一个storage的局部变量,是通过引用传递。所以对于局部变量的修改,同时修改关联的状态变量。另一方面,将一个memory的引用类型赋值给另一个memory的引用,不会创建另一个新的拷贝。
——不同数据类型的变量会有各自默认的存储位置,我们再来回顾一下:
-状态变量总是会存储在storage 中
-函数参数和返回值默认存放在 内存memory 中
-结构、数组或映射类型的局部变量,默认会放在 存储storage 中
-除结构、数组及映射类型之外的简单局部值变量,会储存在栈中
——下面我们来看几个实际的代码块案例
-案例一:memory赋值给局部变量
在上述示例中,我们尝试将一个参数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
当我们把一个storage类型的变量赋值给另一个storage时,我们只是修改了它的指针。在上面的代码中,我们将传入的storage变量,赋值给另一个临时的storage类型的tmp时,并修改tmp.a = "Test",最后我们会发现合约的状态变量s也被修改了。
-案例三:memory赋值给状态变量
将一个memory类型的变量赋值给一个状态变量时,实际是将内存变量拷贝到存储中。在方法中,我们把tmp赋值给s后,再修改tmp值,并不能产生任何变化。赋值时,完成了值的拷贝,后续他们不再有任何的关系。
-案例四:storage转为memory
将storage类型的值转为memory,实际是将数据从storage中拷贝到memory中。在上面的例子中,我们看到,拷贝后对tmp变量的修改,完全不会影响到原来的storage变量。
-案例五:memory转为memory
memory之间的复杂类型的相互赋值实际上是引用的传递,并不会拷贝数据。在上面的代码中,memoryToMemory()传递进来了一个memory类型的变量,在函数内将之赋值给tmp,修改tmp的值,发现外部的memory也被改为了other memory。
——以上就是Solidity中常见的几种存储转换,供参考使用