以太坊智能合约开发:Solidity语言中变量的存储位置与作用域

在Solidity中,有一些数据类型是引用类型,如:

  • 数组(string和bytes是特殊的数组,也是引用类型)
  • 结构体(struct)
  • 映射(mapping)

在Solidity中使用引用类型的时候,必须指定数据的位置。

存储位置

在合约中声明的变量都有一个存储位置,用于指明变量的值存储在哪里。

Solidity提供了三种类型的存储位置:

  • storage
  • memory
  • calldata

storage

链上存储空间。该存储位置用于存储永久数据,只要合约存在数据就一直有效。存储的 Gas 较高。

其中:

  • 状态变量的存储方式强制是 storage
  • 局部变量的存储方式可以声明成 storagememorycalldata
  • 映射(mapping)只能存储在 storage 中。

memory

内存存储。即数据存储在内存中,数据只在其生命周期内(函数调用期间)有效。

calldata

调用数据。一个特殊的只读数据位置,用来存储函数调用的参数(包括内部和外部函数),类似于 memory。使用 calldata 变量的好处是,它不用将数据的副本保存到内存中,并确保不会修改数据。

总结:

  1. 状态变量的存储方式都是 storage
  2. 局部变量的存储方式可以声明成 storagememorycalldata
  3. 公用函数(public)和外部函数(external)中,函数参数的存储方式只能是 memorycalldata
  4. 私有函数(private)和内部函数(internal)中,函数参数的存储方式还可以是 storage
  5. 映射(mapping)只能存储在 storage 中,且不能在函数内部定义,映射一般声明为状态变量;
  6. 一般建议将函数参数和局部变量的存储方式声明为 memory

合约例子

下面是一个合约例子,用来演示数据存储位置的用法。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

// 变量存储位置和作用域
contract DataStorages {
    // 状态变量强制为 storage
    string public str;
    bytes public bs;
    uint[] public arr;
    mapping(address => uint) map;
    struct Student {
        string name;
        uint score;
    }
    Student[] public students;

    // 公共函数(public)和外部函数(external)中,存储位置可以声明成 meomory 和 calldata
    // 私有函数(private)和内部函数(internal)中,存储位置还可以声明成 storage

    // 字符串的存储位置
    function setString(string memory _str) public {
        str = _str;
    }

    // 字节的存储位置
    function setBytes(bytes memory _bs) public {
        bs = _bs;
    }

    // 数组的存储位置
    function setArray(uint[] memory _arr) public {
         for(uint i = 0; i < _arr.length; i++) {
            arr.push(_arr[i]);
        }
    }
    
    // 结构体的存储位置
    function setStruct(Student calldata _student) public {
        students.push(_student);
    }

    // 在内部函数(internal)中,变量可以声明成 storage
    function getLength(uint[] storage _arr) internal view returns(uint) {
        return(_arr.length);
    }

    // 调用内部函数
    function test() public view returns(uint) {
        return getLength(arr);
    }
}

**输出:**我们在Remix中编译、部署和运行这个合约例子,执行结果如下图:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zyq55917/article/details/126156960