引用类型
之前已经介绍过一些值类型了,本文介绍一下引用类型。引用类型是一个复杂类型,占用的空间通常超过256位,所以对于引用类型,必须小心处理。由于拷贝时开销很大,我们需要考虑好是将它们存储在memory(内存中,数据只是临时存储)还是storage(存储状态变量的地方,永久存储在区块链中)
数据位置(Data location)
我个人对数据位置的理解是用一个属性来标识变量是存储在memory(内存)中还是storage(永久存储区块链)中。
每一种复杂的类型,像数组和结构体,都有额外的一种注解--数据位置(Data location),数据位置(Data location)是指数据被存储在memory还是storage,根据上下文环境,数据位置一般有默认值,但是可以通过指定关键字storage和memory修改它。函数参数(包含返回的参数)默认是memory。局部变量和状态变量默认是storage
除了storage和memory之外,还有第三种数据位置,calldata,用于存储函数参数,是不可修改(只读),不会永久存储的数据位置。外部函数的参数(不包括返回参数)被强制指定为calldata,作用与memory差不多。
数据位置指定非常重要,因为他们影响着赋值行为。在memory和storage之间或与状态变量之间相互赋值,总是会创建一个完全独立的拷贝。将一个storage的状态变量,赋值给一个storage的局部变量,是通过引用传递,对于局部变量的修改,同时修改关联的状态变量。另一方面,将一个memory的引用类型赋值给另一个memory的引用,不会创建拷贝(memory之间是引用传递)。
下面的这段代码将帮助你更好的理解上面的概念
pragma solidity ^0.4.0;
contract C {
uint[] x; // x的存储位置是storage
// memoryArray的存储位置是 memory
function f(uint[] memoryArray) public {
x = memoryArray; // 将 memory 赋值给状态变量 x(storage)
var y = x; // 通过引用传递,将x赋值给y,y 是一个 storage 引用
y[7]; // 返回第8个元素
y.length = 2; // y的元素个数被修改为2,x也会被修改(因为是引用传递)
delete x; // 清除数组x,y同样被修改
// 编译不通过,不能将memory赋值给storage局部变量
// y = memoryArray;
// 编译不通过,不能通过引用销毁storage
// delete y;
g(x); // 引用传递 x,在g函数里面可以改变x的值
h(x); // 拷贝到memory, h函数中无法改变x的值
}
function g(uint[] storage storageArray) internal {}
function h(uint[] memoryArray) public {}
}
总结
强制的数据位置(Forced data location)
- 外部函数(External function)的参数(不包括返回参数)强制为:calldata
- 状态变量(State variables)强制为: storage
默认数据位置(Default data location)
- 函数参数(包括返回参数):memory
- 局部变量:storage
更多案例:
https://www.jianshu.com/p/57c78a3e4241
参考:
https://solidity.readthedocs.io/en/develop/types.html#data-location
https://www.jianshu.com/p/57c78a3e4241
https://blog.csdn.net/liyuechun520/article/details/78408588
网友评论