文章详细介绍了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 中,然后为键输入数字,看看返回的零值是什么。
顺便说一下,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 函数返回
}
}
练习题
查看 Solidity 训练营 ,以了解更多关于智能合约开发和代币标准的内容。
- 原文链接: rareskills.io/learn-soli...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!