映射类型
映射类型使用语法,映射类型的变量使用语法声明。可以是任何内置值类型、、或任何合约或枚举类型。不允许使用其他用户定义或复杂类型,例如映射、结构或数组类型。 可以是任何类型,包括映射、数组和结构。mapping(KeyType => ValueType)mapping(KeyType => ValueType) VariableNameKeyTypebytesstringValueType
您可以将映射视为哈希表,它实际上已初始化,使得每个可能的键都存在并映射到字节表示全为零的值,即类型的默认值。相似性到此为止,关键数据不存储在映射中,仅使用其keccak256散列来查找值。
因此,映射没有长度或设置的键或值的概念,因此如果没有有关已分配键的额外信息,就无法擦除(请参阅清除映射)。
映射只能有一个数据位置,storage因此可以用于状态变量,作为函数中的存储引用类型,或者作为库函数的参数。它们不能用作公开可见的合约函数的参数或返回参数。这些限制也适用于包含映射的数组和结构。
您可以将映射类型的状态变量标记为public,Solidity 会为您创建一个 getter。KeyType成为 getter 的参数。如果ValueType是值类型或结构,则 getter 返回ValueType. 如果ValueType是数组或映射,则 getterKeyType递归地为每个 具有一个参数。
在下面的示例中,MappingExample合约定义了一个公共balances 映射,键类型为addressa ,值类型为 a uint,将以太坊地址映射到无符号整数值。作为uint值类型,getter 返回一个与类型匹配的值,你可以在MappingUser 合约中看到返回指定地址的值。
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.9.0; contract MappingExample { mapping(address => uint) public balances; function update(uint newBalance) public { balances[msg.sender] = newBalance; } } contract MappingUser { function f() public returns (uint) { MappingExample m = new MappingExample(); m.update(100); return m.balances(address(this)); } }
下面的示例是 ERC20 代币的简化版本。 _allowances是另一个映射类型中的映射类型的示例。下面的示例_allowances用于记录允许其他人从您的帐户中提取的金额。
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.9.0; contract MappingExample { mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { require(_allowances[sender][msg.sender] >= amount, "ERC20: Allowance not high enough."); _allowances[sender][msg.sender] -= amount; _transfer(sender, recipient, amount); return true; } function approve(address spender, uint256 amount) public returns (bool) { require(spender != address(0), "ERC20: approve to the zero address"); _allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); require(_balances[sender] >= amount, "ERC20: Not enough funds."); _balances[sender] -= amount; _balances[recipient] += amount; emit Transfer(sender, recipient, amount); } }