一起学智能合约之三数据存储位置
一起学智能合约之三数据存储位置
在上一篇介绍变量时,简单的提到过智能合约中的数据存储的位置分为memory 和storage。在本篇将重点介绍一下以太坊智能合约的数据存储的位置和用途以及因此产生的Gas的消耗。
一、存储的位置
现在已经知道Solidity中的变量分为两类:值类型和引用类型。
其实之所以分为两种类型主要还是为了减少合约中应用时的内存的开销。一般来说,大的数据会使用引用类型,而小的数据一般来说采用值类型。无论哪种类型,存储时都要根据实际情况来确定存储在memory中还是storage中。
另外还有特殊的复杂类型,比如数组和结构体,它们会有一个额外的属性来设定为存储在哪个位置。通过一个例子来看一下:
pragma solidity ^0.4.17;
contract Example {
//这两个是状态变量
int public num;
string public name;
//参数是局部变量
function Example (int n,string str) {
num = n;
name = str;
}
function fun(string str) {
//局部变量
var temp = str;
}
}
按照Solidity中的说明:
1、函数参数为引用类型时,默认为memory类型。
2、值类型局部变量一般默认在栈上。
3、函数参数如果指定为storage类型,函数的类型必须为internal或者private.
pragma solidity ^0.4.17;
contract Example {
……
function fun(string storage str) internal {
var temp = str;
}
}
4、函数的返回参数默认是memory类型.
5、合约中的状态变量(合约内的公有变量),强制storage类型。
6、简单类型的局部变量默认是在栈上。
7、复杂类型的局部变量默认是storage类型。
8、一般外部函数的参数(不含返回参数)强制为calldata,只读不上链持久化。
二、数据位置的转换
storage=>storage:类似于引用传递,可以透明修改。
memory=>state:相当于内存拷贝到storage
memory=>local:需要强制为memory类型的变量才可以赋值。
storage=>memory:同理,做一次内存拷贝。
memory=>memory:复杂类型为引用传递,并不会引起数据拷贝。
三、Gas消耗
在Solidity中,不同存储需要消耗不同的gas:
storage: 持久化合约状态变量,费用最高。
memory :仅保存临时变量,函数调用之后释放,开销很小。
stack: 保存很小的局部变量,几乎免费使用,但有数量限制。
黄皮书中和源码中都有一些计算的依据:
四、总结:
通过上面分析可以得出在智能合约中目前有三种存储位置:memory,storage,calldata。特别需要注意的两处指定为强制的地方,一定不能乱来。
尽量控制好存储的位置,可以减少不必要的GAS消耗。