智能合约语言 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是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你先看以太坊是 ...
随机推荐
- 有道云翻译接口 Show类
package com.yangchong.fanyi; import java.awt.EventQueue;import java.awt.Toolkit; import javax.swing. ...
- 修改文件的所有者失(chown: changing ownership of `uploads': Operation not permitted)
在项目开发的时候,经常需要将文件上传到指定的目录下. 例如这次用thinkphp5的时候,需要在public目录下建立uploads目录用于存放上传的资源. 首先在命令窗口下输入: mkdir upl ...
- setInterval计时器延时问题
计时器延时问题 js计时器 使用setTimeout.setInterval函数时,第二个参数的设置的时间间隔t是自该函数(setTimeout(f1,t).setInterval(f1,t))被调用 ...
- filereader api 类型
filereader类似XMLHttpRequest,只是它用来从文件系统读取文件,提供了不同的方法去读取文件数据:1.readAsText2.readAsDataURL3.readAsBinaryS ...
- ASP.NET Core 2.0 集成测试无法执行的问题
问题表现: Microsoft.AspNetCore.Mvc.Razor.Compilation.CompilationFailedException : One or more compilatio ...
- 532. K-diff Pairs in an Array
Given an array of integers and an integer k, you need to find the number of unique k-diff pairs in t ...
- let 和const与var的不同
1. let的作用域在代码块中仅限在当前的作用于中 { var str1 = 12; console.log(str1); let str2 = 20; console.log(str2); //20 ...
- 在vi按了ctrl+s后
习惯了在windows下写程序,也习惯了按ctrl+s 保存代码,在用vi的时候,也习惯性的按ctrl+s 结果就是如同终端死掉了一样. 原来: ctrl+s 终止屏幕输出(即停止回显),你敲的依然有 ...
- SQL Server 在生产环境中这样写存储过程的坑都避免了吗?
概述 最近因为业务的需求写了一段时间存储过程,发现之前写的存储过程存在一些不严谨的地方,特别是TRY...CATCH中嵌套事务的写法:虽然之前写的并没有错,但是还是埋藏着很大的隐患在里面.希望这篇文章 ...
- 解决弹出蒙层滑动穿透问题-vue
最近开发过程中遇到一些小问题(似乎问题总是那么多),但一直没什么时间去优化与解决.程序员不能被业务绑架,有时间还是花点在代码上