智能合约语言 Solidity 教程系列4 - 数据存储位置分析
最新内容会更新在主站深入浅出区块链社区
原文链接:智能合约语言 Solidity 教程系列4 - 数据存储位置分析
写在前面
Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊、智能合约有所了解,
如果你还不了解,建议你先看以太坊是什么
这部分的内容官方英文文档讲的不是很透,因此我在参考Solidity官方文档(当前最新版本:0.4.20)的同时加入了深入分析部分,欢迎订阅专栏。
数据位置(Data location)
在系列第一篇,我们提到 Solidity 类型分为两类:
值类型(Value Type) 及 引用类型(Reference Types),
前面我们已经介绍完了值类型,接下来会介绍引用类型。
引用类型是一个复杂类型,占用的空间通常超过256位, 拷贝时开销很大,因此我们需要考虑将它们存储在什么位置,是memory(内存中,数据不是永久存在)还是storage(永久存储在区块链中)
所有的复杂类型如数组(arrays)和数据结构(struct)有一个额外的属性:数据的存储位置(data location)。可为memory和storage。
根据上下文的不同,大多数时候数据位置有默认值,也通过指定关键字storage和memory修改它。
函数参数(包含返回的参数)默认是memory。
局部复杂类型变量(local variables)和 状态变量(state variables) 默认是storage。
局部变量:局部作用域(越过作用域即不可被访问,等待被回收)的变量,如函数内的变量。状态变量:合约内声明的公有变量
还有一个存储位置是:calldata,用来存储函数参数,是只读的,不会永久存储的一个数据位置。外部函数的参数(不包括返回参数)被强制指定为calldata。效果与memory差不多。
数据位置指定非常重要,因为他们影响着赋值行为。
在memory和storage之间或与状态变量之间相互赋值,总是会创建一个完全独立的拷贝。
而将一个storage的状态变量,赋值给一个storage的局部变量,是通过引用传递。所以对于局部变量的修改,同时修改关联的状态变量。
另一方面,将一个memory的引用类型赋值给另一个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 存储结构是在合约创建的时候就确定好了的,它取决于合约所声明状态变量。但是内容可以被(交易)调用改变。
Solidity 称这个为状态改变,这也是合约级变量称为状态变量的原因。也可以更好的理解为什么状态变量都是storage存储。
memory 只能用于函数内部,memory 声明用来告知EVM在运行时创建一块(固定大小)内存区域给变量使用。
storage 在区块链中是用key/value的形式存储,而memory则表现为字节数组
关于栈(stack)
EVM是一个基于栈的语言,栈实际是在内存(memory)的一个数据结构,每个栈元素占为256位,栈最大长度为1024。
值类型的局部变量是存储在栈上。
不同存储的消耗(gas消耗)
- storage 会永久保存合约状态变量,开销最大
- memory 仅保存临时变量,函数调用之后释放,开销很小
- stack 保存很小的局部变量,几乎免费使用,但有数量限制。
参考视频
我们也推出了目前市面上最全的视频教程:深入详解以太坊智能合约语言Solidity
目前我们也在招募体验师,可以点击链接了解。
参考资料
深入浅出区块链 - 系统学习区块链,打造最好的区块链技术博客
智能合约语言 Solidity 教程系列4 - 数据存储位置分析的更多相关文章
- 智能合约语言Solidity教程系列2 - 地址类型介绍
智能合约语言Solidity教程系列第二篇 - Solidity地址类型介绍. 写在前面 Solidity是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你 ...
- 智能合约语言 Solidity 教程系列6 - 结构体与映射
写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么 本系列文章一部分是参考Solidity官方文档(当前最新版 ...
- 智能合约语言 Solidity 教程系列5 - 数组介绍
写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么 本文前半部分是参考Solidity官方文档(当前最新版本: ...
- 智能合约语言 Solidity 教程系列8 - Solidity API
这是Solidity教程系列文章第8篇介绍Solidity API,它们主要表现为内置的特殊的变量及函数,存在于全局命名空间里. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应 ...
- 智能合约语言 Solidity 教程系列3 - 函数类型
Solidity 教程系列第三篇 - Solidity 函数类型介绍. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你先看以 ...
- 智能合约语言 Solidity 教程系列9 - 错误处理
这是Solidity教程系列文章第9篇介绍Solidity 错误处理. Solidity系列完整的文章列表请查看分类-Solidity. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文 ...
- 智能合约语言 Solidity 教程系列10 - 完全理解函数修改器
这是Solidity教程系列文章第10篇,带大家完全理解Solidity的函数修改器. Solidity系列完整的文章列表请查看分类-Solidity. 写在前面 Solidity 是以太坊智能合约编 ...
- 智能合约语言 Solidity 教程系列7 - 以太单位及时间单位
这是Solidity教程系列文章第7篇介绍以太单位及时间单位,系列带你全面深入理解Solidity语言. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所 ...
- 智能合约语言 Solidity 教程系列2 - 地址类型介绍
Solidity教程系列第二篇 - Solidity地址类型介绍. 写在前面 Solidity是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你先看以太坊是 ...
随机推荐
- 一次线上Mysql数据库崩溃事故的记录
文章简介 工作这几年,技术栈在不断更新,项目管理心得也增加了不少,写代码的速度也在提升,感觉很欣慰,毕竟是在一直进步,但是过程中也有许许多多的曲折,也踩过了数不尽的坑坑洼洼,从一个连百度都不知道用的萌 ...
- 逆向课程第二讲,寻找main入口点
逆向课程第二讲,寻找main入口点 一丶识别各个程序的入口点 入门知识,识别各个应用程序的入口点 (举例识别VC 编译器生成,以及VS编译生成的Debug版本以及Release版本) 1.识别VC6. ...
- C# group 子句
group 子句返回一个 IGrouping<TKey,TElement> 对象序列,这些对象包含零个或更多与该组的键值匹配的项. 例如,可以按照每个字符串中的第一个字母对字符串序列进行分 ...
- 分享如何将git项目导入GitHub(附创建分支)
前言:我们应该很多都会有自己的私有项目,大多情况都是存放在自己的硬盘中,今天我分享一下怎么讲自己的私有项目更新到GitHub上,这样再也不用担心项目丢失了. 一:下载git 下载链接git链接,根据自 ...
- Scrum Meeting Alpha - 10
Scrum Meeting Alpha - 10 NewTeam 2017/11/06 地点:主楼和3号楼之间的走廊2楼 任务反馈 团队成员 完成任务 计划任务 安万贺 完成了对涉及内容修改的API的 ...
- MyEclipse10激活方法
背景:因为以前一直使用的是myeclipse8.6版本,但因为版本太低有些功能不支持,于是想试用下myeclipse10.0版本,但是下载后发现需要激活,但在激活的过程中遇到了很多坑,于是便有了本文的 ...
- [转]SQL Server为啥使用了这么多内存?
原文地址:http://support.microsoft.com/gp/anxin_techtip6/zh-cn SQL Server为啥使用了这么多内存? SQL Server的用户,常常会发现S ...
- Java 中实现方法重试的一种机制
有这样一个需求,当调用某个方法抛出异常,比如通过 HttpClient 调用远程接口时由于网络原因报 TimeOut 异常:或者所请求的接口返回类似于"处理中"这样的信息,需要重复 ...
- 八、VueJs 填坑日记之参数传递及内容页面的开发
我们在上一篇博文中,渲染出来了一个列表,并在列表中使用了router-link标签,标签内的:to就是链接地址,昨天咱们是<router-link :to="'/content/' + ...
- GameObject类及相关API
GameObject.Find(String name):查找一个名为name的游戏物体,并返回这个游戏物体,找不到返回null.(不到万不得已,不要在Update()中使用,建议在Start()中使 ...