存储位置

基础

默认数据位置

状态变量默认storage
内部函数参数默认memory
外部函数参数默认calldata

例如

pragma solidity ^0.8.0;
contract SimpleAssign{ 
    // storage 类型
    struct S{
        string a;
        uint b;
    }
    function assign(S s) internal{ 
        // 函数参数默认是 memory 类型,即 s 是 memory 类型
        // 局部变量默认 storage 类型
        // 将一个memory类型的参数赋值给storage类型的局部变量会报错。
        S tmp = s; // 报错
  }
}

值转换

storage–>storage

把一个storage类型赋值给一个 storage 类型时,只是修改其指针(引用传递)。

memory–>storage

分为 2 种情况: a. 将 memory–>状态变量; 即将内存中的变量拷贝到存储中(值传递)

b.将memeory–>局部变量 报错

storage–>memory

即将数据从storage拷贝到memory中

memory–>memory

和storage转storage一样是引用传递

Memory

概述

存储在内存中,即分配、即使用,越过作用域则不可访问,等待被回收。 内存是易失性读写字节可寻址空间。它主要用于在执行过程中存储数据,主要用于向内部函数传递参数。鉴于这是易失性区域,每个消息调用都以清除内存开始。所有位置最初都定义为零。作为calldata,内存可以按字节级别寻址,但一次只能读取32字节的字。 当我们写入以前未使用过的单词时,内存被称为“扩展”。除了写入本身的成本之外,这种扩展也有成本,前 724 字节呈线性增长,之后呈二次方增长。

特点

操作码

EVM 提供了三个操作码来与内存区域进行交互

Calldata

概述

存储函数参数,它是只读的,不会永久存储的一个数据位置。外部函数的参数被强制指定为 calldata,效果与 memory 类似。

特点

操作码

EVM 提供的用于操作调用数据的操作码

常用操作

Memory变量

Memory变量临时变量(内存型),合约函数执行完成时,内存型变量被移除。 在函数参数或返回值声明时,如果返回数据的类型是变长的,那么需要加memory修饰,例如

等类型都需要使用memory。

storage变量

storage的作用类似于C++中的引用传递,用storage修饰的变量等同于右值的一个分身,对其进行修改也会影响到本尊。

区别

如果数组中的结构体赋值给函数中声明的变量,使用memory修饰获得的是一个副本,也就是拷贝

如果使用storage修饰变量,那么得到的是一个引用,就是p 是指向 persons[_id] 的指针。例如

Last updated