智能合约语言 Solidity 教程 – 数据存储位置分析

智能合约语言 Solidity 教程 – 数据存储位置分析

电报联系方式

数据位置(Data location)

Solidity 类型分为两类:值类型(Value Type) 和 引用类型(Reference Types)

值类型在前面已经介绍过了,这篇文章介绍引用类型。

智能合约语言 Solidity 教程 - 数据存储位置分析

引用类型是一种复杂的数据类型,通常占用的空间超过256位,因此在拷贝时会带来较大的开销。因此,我们需要仔细考虑将这些引用类型存储在何处,即是存储在内存中(memory,数据不是永久性的)还是永久性存储在区块链上(storage)。

对于所有的复杂类型,如数组和结构体,都有一个额外的属性,即数据的存储位置(data location)。这个属性可以被设置为 memorystorage,用以决定数据应该存储在哪个位置。这一选择对于区块链应用程序的效率和资源管理至关重要。

根据上下文的不同,大多数时候数据位置有默认值,也通过指定关键字storage和memory修改它。

函数参数(包含返回的参数)默认是memory
局部复杂类型变量(local variables)和 状态变量(state variables) 默认是storage

局部变量是那些具有局部作用域的变量,它们仅在特定范围内可见,超出该范围后将无法访问,并等待垃圾回收。

状态变量则是合约内部声明的公开变量,它们的值可以被合约中的不同函数访问和修改,而且这些变量的值会永久存储在区块链上。状态变量通常用于存储和跟踪合约的状态信息。

  • 另一个重要的数据位置是 calldata,它用于存储函数参数。值得注意的是,calldata 是只读的,不会永久存储数据,它的行为类似于 memory
  • 在选择数据位置时非常关键,因为它们会影响赋值的行为。当在 memorystorage 之间,或者与状态变量之间进行赋值时,会创建完全独立的拷贝。这意味着对一个变量的修改不会影响到另一个变量的值。
  • 然而,当将一个 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 {}
}

总结

强制的数据位置(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 用于保存局部变量,它的使用几乎是免费的,但有数量限制,通常用于存储较小的数据和计算中间结果。

开发联系:DEXDAO

 

 

© 版权声明

相关文章

暂无评论

暂无评论...