Learning Objectives – after this chapter you will be able to:
  • Declare and use mappings, including nested mappings.
  • State which key and value types are allowed.
  • Explain default values, getters and why mappings cannot be iterated or measured.
  • Combine a mapping with an array to make data iterable.
Mapping
  • A mapping stores data as key → value pairs, like a hash table or dictionary in other languages. A common example links Ethereum addresses to balances.
  • Think of a mapping as a table in which every possible key already exists and initially holds the default value of the value type (0, false, empty string …).
Syntax
mapping(KeyType => ValueType) <visibility> <name>;
mapping(address => uint) public balances;
mapping(address user => uint balance) public named;   // named keys/values (0.8.18+)
  • KeyType − any built-in value type (uint, address, bool, bytes32 …), bytes, string, a contract type or an enum. Mappings, structs and arrays cannot be keys.
  • ValueType − any type, including structs, arrays and other mappings.
Please Note
  • Mappings can only be stored in storage – they are used as state variables (or storage references). They cannot be created in memory.
  • A mapping can be marked public; Solidity then creates a getter that takes the key as a parameter, e.g. balances(addr).
  • The keys themselves are not stored; the value’s location is calculated from the hash (keccak256) of the key. Therefore a mapping has no length and cannot be iterated.
  • You cannot tell whether a key was “set to 0” or “never set” – both read as 0. Use an extra bool or a struct field if you need to know.
  • delete balances[addr] resets that key’s value to the default.
Nested Mappings

The value of a mapping can itself be a mapping – for example, how much each owner allows each spender to use (the ERC-20 allowance pattern):

mapping(address => mapping(address => uint)) public allowance;
// allowance[owner][spender] = amount;
Example : Student Marks Register
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract MarksRegister {
    mapping(uint => uint) public marksOf;            // roll number => marks
    mapping(uint => bool) public isRegistered;       // to tell "0 marks" from "not set"
    mapping(address => mapping(uint => bool)) public canEdit;   // nested mapping
    uint[] public rollNumbers;                       // array of keys => makes data iterable
    address public teacher;

    constructor() {
        teacher = msg.sender;
    }

    function setMarks(uint roll, uint marks) external {
        require(msg.sender == teacher || canEdit[msg.sender][roll], "Not allowed");
        if (!isRegistered[roll]) {
            isRegistered[roll] = true;
            rollNumbers.push(roll);
        }
        marksOf[roll] = marks;
    }

    function allowEditor(address editor, uint roll) external {
        require(msg.sender == teacher, "Only teacher");
        canEdit[editor][roll] = true;
    }

    function totalMarks() external view returns (uint total) {
        for (uint i = 0; i < rollNumbers.length; i++) {
            total += marksOf[rollNumbers[i]];
        }
    }

    function removeMarks(uint roll) external {
        require(msg.sender == teacher, "Only teacher");
        delete marksOf[roll];                        // value back to 0
    }
}
Key Takeaways
  • mapping(Key => Value) gives fast key look-ups; every key starts at the default value.
  • Mappings live only in storage, have no length and cannot be looped over directly.
  • Keep a separate array of keys (or a flag) when you need to iterate or detect unset keys.
Download | Print      E-Notes

The PDF E-Notes are the earlier printable version of this chapter. The notes on this page are the latest, revised version.

Video : Mapping in Solidity
Resource File
Question / Answer (15 questions)

Answer : Like a hash table or dictionary, a mapping stores key-value pairs and gives direct access to a value by its key. The location of each value is computed from a hash (keccak256) of the key.

Answer : mapping(KeyType => ValueType) visibility name;, for example mapping(address => uint) public balances;.

Answer : Any built-in value type (uint, address, bool, bytes32 …), bytes, string, contract types and enums. Mappings, structs and arrays cannot be used as keys.

Answer : Any type, including structs, arrays and other mappings.

Answer : The default value of the value type – for example 0 for uint, false for bool or the zero address for address.

Answer : The keys are not stored; only values are stored at locations derived from key hashes. Since the contract does not know which keys were used, it cannot count or iterate them.

Answer : Maintain a separate array that stores every key when it is first added, then loop over the array and read each key’s value from the mapping.

Answer : Only storage. Mappings are used as state variables or storage references and cannot be created in memory.

Answer : An external view function balances(address) that takes a key and returns the corresponding value.

Answer : A mapping whose value type is another mapping, e.g. mapping(address => mapping(address => uint)) allowance;, used in ERC-20 tokens to store how much each owner allows each spender to use.

Answer : Both read as 0, so store extra information such as a separate mapping(key => bool) isRegistered or a struct with an exists flag.

Answer : It resets the value for that key to its default (0). The key itself is not “removed” because keys are never stored.

Answer : Since Solidity 0.8.18 you can name the key and value for readability, e.g. mapping(address user => uint balance) balances;. The names do not change behaviour.

Answer : A mapping finds a value directly in constant time and cost, while searching an array requires a loop whose gas cost grows with the array size.

Answer : It records each registered roll number so that totalMarks() can loop over all keys, something the mapping alone cannot do.
MCQ Test : Check Your Understanding (5 questions)

Select an option and press Check Answer, or answer all questions and press Submit Test to see your score. Each answer comes with an explanation.

Q1. Which of these CANNOT be used as a mapping key?

Show Answer

Correct Answer : D. struct
Structs, arrays and mappings cannot be keys.

Q2. Reading balances[x] for an address never set returns:

Show Answer

Correct Answer : A. 0
Unset keys return the default value.

Q3. Mappings can be stored in:

Show Answer

Correct Answer : C. storage only
Mappings exist only in storage.

Q4. Which statement is TRUE about mappings?

Show Answer

Correct Answer : B. They cannot be iterated directly
Keys are not stored, so mappings cannot be iterated.

Q5. mapping(address => mapping(address => uint)) is an example of a:

Show Answer

Correct Answer : A. Nested mapping
The value of the outer mapping is another mapping.

Bibliography/References

The notes, questions and MCQs on this page are original explanations written for this course. The works listed below were consulted and are cited for attribution and further reading. Product names, logos and trademarks belong to their respective owners. Short quotations, where used, are marked and attributed.

  1. Solidity Team. (n.d.). Types (value types, reference types, mappings, operators, conversions). Solidity Documentation. https://docs.soliditylang.org/en/latest/types.html
  2. Solidity Team. (n.d.). Layout of State Variables in Storage. Solidity Documentation. https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html
  3. Vogelsteller, F., & Buterin, V. (2015). ERC-20: Token Standard. Ethereum Improvement Proposals, no. 20. https://eips.ethereum.org/EIPS/eip-20
  4. Solidity Team. (n.d.). Cheatsheet. Solidity Documentation. https://docs.soliditylang.org/en/latest/cheatsheet.html
  5. Modi, R. (2018). Solidity Programming Essentials: A beginner’s guide to build smart contracts for Ethereum and blockchain. Packt Publishing. ISBN 978-1-78883-138-3.