Solidty 映射

文章详细介绍了Solidity中的映射(mapping)功能,解释了其用法、限制以及在实际智能合约中的应用,特别是ERC20代币的实现。

映射、哈希表、关联数组,无论你想怎么称呼它,Solidity 都有。

我们将其称为“映射”,因为这是 Solidity 使用的关键字。让我们来看一个例子。

contract ExampleContract {

    mapping(uint256 => uint256) public myMapping;

    function setMapping(uint256 key, uint256 value)
        public {
            myMapping[key] = value;
    }

    function getValue(uint256 key)
        public
        view
        returns (uint256) {
            return myMapping[key];
    }
}

这段代码的功能正如你所想的那样。由于 myMapping 是 public 的,Solidity 会为其自动生成一个 getter 函数,你可以直接访问这些值。但是,如果你想通过函数访问映射,你可以遵循 getValue 中的模式。

这是第一个令人惊讶的事情:

如果你访问一个映射中尚未设置键的值,你不会收到 revert 错误。映射将仅返回该数据类型的“零值”。

在下面的例子中,如果你提供一个尚未设置的数字,映射将返回 false

contract ExampleContract {
    // 默认返回 false
    mapping(uint256 => bool) public mapToBool;

    // 默认返回 0
    mapping(uint256 => uint256) public mapToUint;

    // 默认返回 0x0000000000000000000000000000000000000000
    mapping(uint256 => address) public mapToAddress;
}

我鼓励你将这段代码粘贴到 Remix 中,然后为键输入数字,看看返回的零值是什么。

https://static.wixstatic.com/media/61a666_499ad0d908c24c7d8cb892b11941611e~mv2.png/v1/crop/x_2,y_0,w_1998,h_972/fill/w_939,h_457,al_c,q_95,enc_auto/Mappings.png

顺便说一下,ERC20 代币使用映射来存储某个人拥有多少代币!它们将地址映射到某个人拥有的代币数量。

contract ERC20Token {

    mapping(address => uint256) public balances;

    function setSomeonesBalance(address owner, uint256 amount)
        public {
            balances[owner] = amount;
    }

    function transferTokensBetweenAddresses(
            address sender,
            address receiver,
            uint256 amount)
        public {
            balances[sender] -= amount;   // 扣除/借记发送者的余额
            balances[receiver] += amount; // 贷记接收者的余额
    }
}

这个实现有一个缺陷,任何人都可以调用 public 函数并在地址之间随意发送代币,但我们稍后会修复这个问题。

与直觉相反的是,ERC20 代币并不存储在加密货币钱包中,它们只是智能合约中与你的地址关联的一个 uint256。“ERC20 代币”只是一个智能合约。

以下是 USDC(一种 ERC20 代币)的智能合约:https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48

这是 ApeCoin 的代币,Bored Ape Yacht Club 生态系统的货币:https://etherscan.io/token/0x4d224452801aced8b2f0aebe155379bb5d594381

惊讶之处 1:映射只能声明为存储变量,你不能在函数内部声明它们

这可能看起来是一个非常奇怪的限制,但这与以太坊虚拟机的工作方式有关。区块链通常不喜欢哈希表,因为它们的运行时行为不可预测。以下代码是无效的。

contract BrokenContract {

    function wontWork()
        public
        view {
            mapping(uint256 => uint256) someMap;
            // 这将无法编译,映射必须是状态变量
    }
}

惊讶之处 2:映射无法遍历

没有办法遍历映射的键。从技术上讲,每个键都是有效的,它只是默认为零。

contract BrokenContract {
    mapping(uint256 => uint256) public someMap;

    function wontWork()
        public
        view {
            for (uint256 key in someMap) {
            // 修正为有效的 Solidity 语法,尽管逻辑仍然无法在 Solidity 中编译
                // 做一些事情
            }
    }
}

惊讶之处 3:映射无法返回

以下代码是无效的。映射不是 Solidity 函数的有效返回类型。

contract BrokenContract {
    mapping(uint256 => uint256) public someMap;

    function wontWork()
        public
        view
        returns (mapping(uint256 => uint256)) {
            return someMap; // 这将无法编译,因为映射无法从 public 函数返回
    }
}

练习题

SpecialNumbers

学习更多

查看 Solidity 训练营 ,以了解更多关于智能合约开发和代币标准的内容。

  • 原文链接: rareskills.io/learn-soli...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/