回顾一下 solidity 中数据位置,即说明数据存储在哪里,solidity 有 3 个位置:

    1. memory : (内存) 即数据在内存中,因此数据仅在其生命周期内(函数调用期间)有效。
    2. storage :(链上存储空间),就是状态变量保存的位置,只要合约存在就一直存储.
    3. calldata :(调用数据),一个特殊只读数据位置,用来保存函数调用参数(之前仅针对外部函数)。

    在 Solidity 中使用引用类型的时候,必须指定数据的位置, 关于数据位置,可以阅读登链社区翻译的Solidity文档-引用类型
    从 Solidity 0.6.9 版本开始,之前仅用于外部函数(external 修饰的函数)的calldata位置,现在可以在内部函数( internal修饰的函数 )使用了。
    请注意,由于EVM不允许修改 calldata,因此无法在 calldata 变量中创建新值或将某些内容复制到 calldata变量。
    以下是一段示例使用 calldata 的 代码:

    1. // SPDX-License-Identifier: GPL-3.0
    2. pragma solidity >=0.6.9;
    3. contract C {
    4. address[] owners;
    5. function addOwners(address[] calldata _newOwners) public {
    6. // We pass _newOwners on as a calldata array.
    7. checkUnique(_newOwners);
    8. for (uint i = 0; i < _newOwners.length; i++)
    9. owners.push(_newOwners[i]);
    10. }
    11. /// 内部函数可以遍历 calldata 的数组,而不用再复制到内存了。
    12. function checkUnique(address[] calldata _newOwners) internal pure {
    13. for (uint i = 0; i < _newOwners.length; i++)
    14. for (uint j = i + 1; i < _newOwners.length; j++)
    15. require(_newOwners[i] != _newOwners[i]);
    16. }
    17. }

    使用 calldata 变量的好处是,它不用将 calldata 数据的副本保存到内存中,并确保不会修改数组或结构(calldata 位置是只读的),因此,如果可以的话,请尽量使用 calldata 作为数据位置
    函数的返回值中其实也可以使用 calldata 数据位置,但是无法给其分配空间。