{"content":{"title":"Solidty 映射","body":"映射、哈希表、关联数组，无论你想怎么称呼它，Solidity 都有。\r\n\r\n我们将其称为“映射”，因为这是 Solidity 使用的关键字。让我们来看一个例子。\r\n\r\n```solidity\r\ncontract ExampleContract {\r\n\r\n    mapping(uint256 => uint256) public myMapping;\r\n\r\n    function setMapping(uint256 key, uint256 value)\r\n        public {\r\n            myMapping[key] = value;\r\n    }\r\n\r\n    function getValue(uint256 key)\r\n        public\r\n        view\r\n        returns (uint256) {\r\n            return myMapping[key];\r\n    }\r\n}\r\n```\r\n\r\n这段代码的功能正如你所想的那样。由于 myMapping 是 public 的，Solidity 会为其自动生成一个 getter 函数，你可以直接访问这些值。但是，如果你想通过函数访问映射，你可以遵循 **getValue** 中的模式。\r\n\r\n这是第一个令人惊讶的事情：\r\n\r\n**如果你访问一个映射中尚未设置键的值，你不会收到 revert 错误。映射将仅返回该数据类型的“零值”。**\r\n\r\n在下面的例子中，如果你提供一个尚未设置的数字，映射将返回 _false_。\r\n\r\n```solidity\r\ncontract ExampleContract {\r\n    // 默认返回 false\r\n    mapping(uint256 => bool) public mapToBool;\r\n\r\n    // 默认返回 0\r\n    mapping(uint256 => uint256) public mapToUint;\r\n\r\n    // 默认返回 0x0000000000000000000000000000000000000000\r\n    mapping(uint256 => address) public mapToAddress;\r\n}\r\n```\r\n\r\n我鼓励你将这段代码粘贴到 Remix 中，然后为键输入数字，看看返回的零值是什么。\r\n\r\n![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](https://img.learnblockchain.cn/2025/02/26/Mappings.png)\r\n\r\n顺便说一下，ERC20 代币使用映射来存储某个人拥有多少代币！它们将地址映射到某个人拥有的代币数量。\r\n\r\n```solidity\r\ncontract ERC20Token {\r\n\r\n    mapping(address => uint256) public balances;\r\n\r\n    function setSomeonesBalance(address owner, uint256 amount)\r\n        public {\r\n            balances[owner] = amount;\r\n    }\r\n\r\n    function transferTokensBetweenAddresses(\r\n            address sender,\r\n            address receiver,\r\n            uint256 amount)\r\n        public {\r\n            balances[sender] -= amount;   // 扣除/借记发送者的余额\r\n            balances[receiver] += amount; // 贷记接收者的余额\r\n    }\r\n}\r\n```\r\n\r\n这个实现有一个缺陷，任何人都可以调用 public 函数并在地址之间随意发送代币，但我们稍后会修复这个问题。\r\n\r\n与直觉相反的是，**ERC20 代币并不存储在加密货币钱包中，它们只是智能合约中与你的地址关联的一个 [uint256](https://learnblockchain.cn/article/11251)**。“ERC20 代币”只是一个智能合约。\r\n\r\n以下是 USDC（一种 ERC20 代币）的智能合约：[https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48](https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48)\r\n\r\n这是 ApeCoin 的代币，Bored Ape Yacht Club 生态系统的货币：[https://etherscan.io/token/0x4d224452801aced8b2f0aebe155379bb5d594381](https://etherscan.io/token/0x4d224452801aced8b2f0aebe155379bb5d594381)\r\n\r\n**惊讶之处 1：映射只能声明为存储变量，你不能在函数内部声明它们**\r\n\r\n这可能看起来是一个非常奇怪的限制，但这与以太坊虚拟机的工作方式有关。区块链通常不喜欢哈希表，因为它们的运行时行为不可预测。以下代码是无效的。\r\n\r\n```solidity\r\ncontract BrokenContract {\r\n\r\n    function wontWork()\r\n        public\r\n        view {\r\n            mapping(uint256 => uint256) someMap;\r\n            // 这将无法编译，映射必须是状态变量\r\n    }\r\n}\r\n```\r\n\r\n**惊讶之处 2：映射无法遍历**\r\n\r\n没有办法遍历映射的键。从技术上讲，每个键都是有效的，它只是默认为零。\r\n\r\n```solidity\r\ncontract BrokenContract {\r\n    mapping(uint256 => uint256) public someMap;\r\n\r\n    function wontWork()\r\n        public\r\n        view {\r\n            for (uint256 key in someMap) {\r\n            // 修正为有效的 Solidity 语法，尽管逻辑仍然无法在 Solidity 中编译\r\n                // 做一些事情\r\n            }\r\n    }\r\n}\r\n```\r\n\r\n**惊讶之处 3：映射无法返回**\r\n\r\n以下代码是无效的。映射不是 Solidity 函数的有效返回类型。\r\n\r\n```solidity\r\ncontract BrokenContract {\r\n    mapping(uint256 => uint256) public someMap;\r\n\r\n    function wontWork()\r\n        public\r\n        view\r\n        returns (mapping(uint256 => uint256)) {\r\n            return someMap; // 这将无法编译，因为映射无法从 public 函数返回\r\n    }\r\n}\r\n```\r\n\r\n**练习题**\r\n\r\n[SpecialNumbers](https://github.com/RareSkills/Solidity-Exercises/tree/main/SpecialNumbers)\r\n\r\n###   学习更多\r\n\r\n查看  [Solidity 训练营](https://learnblockchain.cn/openspace/1) ，以了解更多关于智能合约开发和代币标准的内容。\r\n\r\n \r\n\r\n>- 原文链接： [rareskills.io/learn-soli...](https://www.rareskills.io/learn-solidity/mapping)\r\n>- 登链社区 AI 助手，为大家转译优秀英文文章，如有翻译不通的地方，还请包涵～"},"author":{"user":"https://learnblockchain.cn/people/20722","address":null},"history":null,"timestamp":1740625403,"version":1}