智能合约语言 Solidity 教程 - 数据存储位置分析
Smart Contracts语言 Solidity 教程 - 数据存储位置Analysis
数据位置(Data location)
Solidity 类型分为两类:值类型(Value Type) 和 引用类型(Reference Types)
值类型在前面已经介绍过了,这篇文章介绍引用类型。

引用类型是一种复杂的数据类型,通常占用的空间超过256位,因此在拷贝时会带来较大的开销。因此,我们需要仔细考虑将这些引用类型存储在何处,即是存储在内存中(memory
,数据不是永久性的)还是永久性存储在区块链上(storage
).
对于所有的复杂类型,如数组和结构体,都有一个额外的属性,即数据的存储位置(data location
)。这个属性可以被设置为 memory
or storage
,用以决定数据应该存储在哪个位置。这一选择对于区块链应用程序的效率和资源管理至关重要。
根据上下文的不同,大多数时候数据位置有默认值,也通过指定关键字storage和memory修改它。
函数参数(包含返回的参数)默认是memory.
局部复杂类型变量(local variables)和 状态变量(state variables) 默认是storage.
局部变量是那些具有局部作用域的变量,它们仅在特定范围内可见,超出该范围后将无法访问,并等待垃圾回收。
状态变量则是合约内部声明的公开变量,它们的值可以被合约中的不同函数访问和修改,而且这些变量的值会永久存储在区块链上。状态变量通常用于存储和跟踪合约的状态信息。
- 另一个重要的数据位置是
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 复制到 storage
var y = x; // storage 引用传递局部变量y(y 是一个 storage 引用)
y[7]; // 返回第8个元素
y.length = 2; // x同样会被修改
delete x; // y同样会被修改// 错误, 不能将memory赋值给局部变量
// y = memoryArray;// 错误,不能通过引用销毁storage
// delete y;g(x); // 引用传递, g可以改变x的内容
h(x); // 拷贝到memory, h无法改变x的内容
}function g(uint[] storage storageArray) internal {}
function h(uint[] memoryArray) public {}
}
To sum up
强制的数据位置(Forced data location)
- 外部函数(External function)的参数(不包括返回参数)强制为:calldata
- 状态变量(State variables)强制为: storage
默认数据位置(Default data location)
- 函数参数及返回参数:memory
- 复杂类型的局部变量:storage
深入分析
storage
存储结构是在合约创建时根据合约声明的状态变量确定的。这个结构在合约创建后是不变的,它取决于合约中定义的状态变量。然而,合约中的数据可以通过交易调用来改变,这意味着虽然结构不变,但存储的内容可以随着时间的推移而变化。
memory
只能在函数内部使用,它的声明用来指示以太坊虚拟机(EVM)在运行时为变量分配一块固定大小的内存区域。这个内存区域仅在函数执行期间存在,用于临时存储数据,函数执行结束后将被释放。
关于栈(stack)
EVM是一个基于栈的语言,栈实际是在内存(memory)的一个数据结构,每个栈元素占为256位,栈最大长度为1024。值类型的局部变量是存储在栈上。
不同存储的消耗(gas消耗)
storage
用于永久保存合约状态变量,但开销最大,因为这些变量的值会永久存储在区块链上。memory
用于保存临时变量,只在函数调用期间存在,因此开销很小,它在函数执行结束后会被释放。stack
用于保存局部变量,它的使用几乎是免费的,但有数量限制,通常用于存储较小的数据和计算中间结果。
Please specify source if reproduced智能合约语言 Solidity 教程 - 数据存储位置分析 | Dexnav 区块链导航网