**     storage、memory 和 calldata 是数据存储位置的关键概念,用于控制变量的存储方式和生命周期。**

1. Storage

  • 功能: 用于链上持久化存储变量。变量存储在以太坊区块链的状态中,即合约的存储空间。

  • 特点:

    • 持久化,函数调用结束后仍然存在。

    • 写入和读取成本较高(消耗较多 Gas)。

    • 默认用于状态变量。

  • 使用场景:

    • 保存需要持久化的数据(如用户余额、合约状态等)。

    • 定义合约级别的状态变量。

pragma solidity ^0.8.0;

contract StorageExample {
    uint256 public storedValue; // 默认是 storage

    function setValue(uint256 _value) public {
        storedValue = _value; // 数据持久化存储在区块链上
    }

    function getValue() public view returns (uint256) {
        return storedValue; // 从 storage 中读取
    }
}

2. Memory

  • 功能: 用于函数执行时的临时数据存储。变量只存在于函数调用期间,调用结束后被销毁。

  • 特点:

    • 非持久化,函数调用完成后即丢失。

    • 读取和写入速度快,Gas 成本低。

    • 常用于函数内部的局部变量。

  • 使用场景:

    • 函数中的临时计算。

    • 传递或处理数据结构(如数组、字符串)。

pragma solidity ^0.8.0;

contract MemoryExample {
    function multiply(uint256 a, uint256 b) public pure returns (uint256) {
        uint256 result = a * b; // 局部变量存储在 memory 中
        return result;
    }

    function reverseArray(uint256[] memory arr) public pure returns (uint256[] memory) {
        uint256 len = arr.length;
        uint256[] memory reversed = new uint256[](len); // 临时数组存储在 memory 中
        for (uint256 i = 0; i < len; i++) {
            reversed[i] = arr[len - 1 - i];
        }
        return reversed;
    }
}

3. Calldata

  • 功能: 专用于外部函数的输入参数。存储在调用数据中,变量只读且不可修改。

  •  特点:

    • 不可更改,只能读取。

    • Gas 成本最低,直接引用调用者提供的数据。

    • 必须用于 external 函数的动态大小参数(如数组或字符串)。

  • 使用场景:

    • 外部函数接收用户输入的不可变数据。

    • 提升效率,避免数据复制。

pragma solidity ^0.8.0;

contract CalldataExample {
    function sumArray(uint256[] calldata arr) external pure returns (uint256) {
        uint256 sum = 0;
        for (uint256 i = 0; i < arr.length; i++) {
            sum += arr[i]; // 直接从 calldata 中读取
        }
        return sum;
    }
}

对比总结

对比总结

实战示例:结合三者使用

pragma solidity ^0.8.0;

contract DataExample {
    // 状态变量存储在 storage 中
    uint256[] public storageArray;

    // 添加元素到存储数组
    function addToStorage(uint256 _value) public {
        storageArray.push(_value); // 修改 storage,消耗较高 Gas。
    }

    // 处理临时数组数据
    function processInMemory(uint256[] memory inputArray) public pure returns (uint256) {
        uint256 sum = 0;
        for (uint256 i = 0; i < inputArray.length; i++) {
            sum += inputArray[i]; // 临时存储在 memory 中。
        }
        return sum;
    }

    // 外部调用传递不可变数据
    function readFromCalldata(uint256[] calldata inputArray) external pure returns (uint256) {
        return inputArray.length; // 直接读取 calldata,节省 Gas。
    }
}

如何选择:

• storage:对于需要持久存储的数据(状态变量),必须使用。

• memory:在函数内部使用临时数据时,尤其是小型结构或数组。

• calldata:对于外部函数调用的大型数组或只读参数,使用 calldata 可以显著节省 Gas。

Mirror文章信息

Mirror原文:查看原文

作者地址:0xc994Df6BD78b5e78D4E820A57d65b4EFd33bf936

内容类型:application/json

应用名称:MirrorXYZ

内容摘要:APNbqPIr7MIPuUWfQwyNP1mDiVFy02Sd5vRi9NOI0DU

原始内容摘要:656Hvv0xjbWOYVAYyJXoia2Rg0pVoPoewXG3ije0rDw

区块高度:1561742

发布时间:2024-12-05 09:05:03