写在前面

Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊、智能合约有所了解,

如果你还不了解,建议你先看以太坊是什么

这部分的内容官方英文文档讲的不是很透,因此我在参考Solidity官方文档(当前最新版本:0.4.20)的同时加入了深入分析部分,欢迎订阅专栏

数据位置(Data location)

在系列第一篇,我们提到 Solidity 类型分为两类:

值类型(Value Type)引用类型(Reference Types)

前面我们已经介绍完了值类型,接下来会介绍引用类型。

引用类型是一个复杂类型,占用的空间通常超过256位, 拷贝时开销很大,因此我们需要考虑将它们存储在什么位置,是memory(内存中,数据不是永久存在)还是storage(永久存储在区块链中)

所有的复杂类型如数组(arrays)和数据结构(struct)有一个额外的属性:数据的存储位置(data location)。可为memorystorage

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

函数参数(包含返回的参数)默认是memory

局部复杂类型变量(local variables)和 状态变量(state variables) 默认是storage

局部变量:局部作用域(越过作用域即不可被访问,等待被回收)的变量,如函数内的变量。状态变量:合约内声明的公有变量

还有一个存储位置是:calldata,用来存储函数参数,是只读的,不会永久存储的一个数据位置。外部函数的参数(不包括返回参数)被强制指定为calldata。效果与memory差不多。

数据位置指定非常重要,因为他们影响着赋值行为。

在memory和storage之间或与状态变量之间相互赋值,总是会创建一个完全独立的拷贝。

而将一个storage的状态变量,赋值给一个storage的局部变量,是通过引用传递。所以对于局部变量的修改,同时修改关联的状态变量。

另一方面,将一个memory的引用类型赋值给另一个memory的引用,不会创建拷贝(即:memory之间是引用传递)。

  1. 注意:不能将memory赋值给局部变量。
  2. 对于值类型,总是会进行拷贝。

下面看一段代码:

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 - 数据存储位置分析的更多相关文章

  1. 智能合约语言Solidity教程系列2 - 地址类型介绍

    智能合约语言Solidity教程系列第二篇 - Solidity地址类型介绍. 写在前面 Solidity是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你 ...

  2. 智能合约语言 Solidity 教程系列8 - Solidity API

    这是Solidity教程系列文章第8篇介绍Solidity API,它们主要表现为内置的特殊的变量及函数,存在于全局命名空间里. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应 ...

  3. 智能合约语言 Solidity 教程系列7 - 以太单位及时间单位

    这是Solidity教程系列文章第7篇介绍以太单位及时间单位,系列带你全面深入理解Solidity语言. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所 ...

  4. 智能合约语言 Solidity 教程系列2 - 地址类型介绍

    Solidity教程系列第二篇 - Solidity地址类型介绍. 写在前面 Solidity是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你先看以太坊是 ...

  5. 智能合约语言 Solidity 教程系列9 - 错误处理

    这是Solidity教程系列文章第9篇介绍Solidity 错误处理. Solidity系列完整的文章列表请查看分类-Solidity. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文 ...

  6. 智能合约语言 Solidity 教程系列3 - 函数类型

    Solidity 教程系列第三篇 - Solidity 函数类型介绍. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你先看以 ...

  7. 智能合约语言 Solidity 教程系列1 - 类型介绍

    现在的Solidity中文文档,要么翻译的太烂,要么太旧,决定重新翻译下.尤其点名批评极客学院名为<Solidity官方文档中文版>的翻译,机器翻译的都比它好,大家还是别看了. 写在前面 ...

  8. 智能合约语言 Solidity 教程系列6 - 结构体与映射

    写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么 本系列文章一部分是参考Solidity官方文档(当前最新版 ...

  9. 智能合约语言 Solidity 教程系列5 - 数组介绍

    写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么 本文前半部分是参考Solidity官方文档(当前最新版本: ...

随机推荐

  1. vim 基本使用

    vim 下基本命令 重新加载 .vimrc source ~/.vimrc 列出当前缓冲区的所有文档 ls 然后使用 b+编号 移至该文档 选中多行 v + shift 然后 j k 上下移动 缩进单 ...

  2. android.view.InflateException: Binary XML file line #34: Error inflating class

    问题一般出在xml的第三方View的全类名,你可能是直接粘贴过来的,没有改成自己项目的全类名.

  3. sicily 1934. 移动小球

    Description 你有一些小球,从左到右依次编号为1,2,3,...,n. 你可以执行两种指令(1或者2).其中, 1 X Y表示把小球X移动到小球Y的左边, 2 X Y表示把小球X移动到小球Y ...

  4. thinkphp-许愿墙-3

    用jquery写异步传递的时候, 首先要判断表单中的输入是否为空: 如果有多个输入项, 应该, 分别的, 一步一步的来判断是否为空, 而不是用 and / or来复合判断! 同时如果为空, 应该将它设 ...

  5. Callable接口、Runable接口、Future接口

    1. Callable与Runable区别 Java从发布的第一个版本开始就可以很方便地编写多线程的应用程序,并在设计中引入异步处理.Thread类.Runnable接口和Java内存管理模型使得多线 ...

  6. linux性能测试命令-----top

    Top命令显示了实际CPU使用情况,默认情况下,它显示了服务器上占用CPU的任务信息,并且每5秒钟刷新一次.它会显示CPU使用量.内存使用量.交换内存.缓存大小.缓冲区大小.流程PID.用户.命令等. ...

  7. 添加数据之后不跳页面显示一个漂亮的提示信息(非ajax提交数据)

    1.在后台设置一个添加成功与否的提示 2.在添加页面设置提示信息 (自己喜欢什么样式就条成什么样式) 3.写js控制提示信息的显示与消失

  8. 如何在ASP.Net中实现RSA加密

    在我们实际运用中,加密是保证数据安全的重要手段.以前使用ASP时,对数据加密可以使用MD5和SHA1算法,这两种算法虽然快捷有效,但是无法对通过它们加密的密文进行反运算,即是解密.因此需要解密数据的场 ...

  9. 《android传感器高级编程》译者序

    翻看手机中的应用,就能发现大多数应用都已经使用了传感器.让微信彻底火起来的“附近的人”和“摇一摇”.碰一碰交换信息的Bump.各种运动记录app.神奇的“磁力探测仪”.火爆的游戏Temple Run… ...

  10. 位运算(bit)

    位运算(bit) Time Limit:2000ms   Memory Limit:64MB [题目描述] lyk最近在研究位运算.它发现除了xor,or,and外还有很多运算.它新定义了一种运算符“ ...