[Ethereum] How does Mapping in solidity work


I went through the Crowdfunding example in solidity where i encountered the following:

contract Crowdfunding {
struct CampaignData {
    address recipient;
    uint contributed;
    uint goal;
    uint deadline;
    uint num_contributions;
    mapping(uint => Contribution) contributions;

struct Contribution {
    address contributor;
    uint amount;

uint nextCampaignId;
mapping(uint256 => CampaignData) campaigns;

// Start a new campaign.
function start(address recipient, uint256 goal, uint256 deadline) returns (uint id) {
    var campaign = campaigns[nextCampaignId];
    campaign.recipient = recipient;
    campaign.goal = goal;
    campaign.deadline = deadline;
    nextCampaignId ++;
    id = nextCampaignId;

What is really happening here?

Why did we use mapping? How is it helping us? I couldn't understand the working of it and hence not able to use it.

Best Answer

Anatomy of a Mapping

A mapping is used to structure value types, such as booleans, integers, addresses, and structs. It consists of two main parts: a _KeyType and a _ValueType; they appear in the following syntax:

mapping (_KeyType => _ValueType) mapName

In the example contract provided above,

mapping (uint256 => CampaignData) campaigns

the uint256 is the _KeyType and the CampaignData is the _ValueType. Note for later that the _ValueType, CampaignData, is a struct.

Mapping Value Types to Key Types

Think of the _KeyType as the key you'll pass through a function to be returned a desired value, or _ValueType. By default, a mapping is initially empty, so new a _KeyType will first need to be mapped to a _ValueType.

The example contract's start function handles 3 basic processes: (1) giving a _KeyType to a new _ValueType CampaignData struct; (2) populating the new CampaignData struct with variable values; and (3) procuring a new _KeyType nextCampaignID to be ready on deck for the next time the example contract's start function is called. This segments of the function can be dissected like so:

(1) giving a _KeyType to a new _ValueType CampaignData struct:

    var campaign = campaigns[nextCampaignId];

In this line, nextCampaignId is mapped as the _KeyType, and the new campaign struct is the _ValueType.

(2) populating the new CampaignData struct with variable values:

    campaign.recipient = recipient;
    campaign.goal = goal;
    campaign.deadline = deadline;

(3) procuring a new _KeyType nextCampaignID for the next time the function is called:

    nextCampaignId ++;

Using a mapping here is helpful because a mapping can store many _KeyTypes to _ValueTypes - in this case if there are many campaigns occurring at once they can each have their own campaignID. Each campaign having its own ID is powerful when calling for CampaignData in future functions.

Accessing Value Types from a Mapping with Key Types

This example contract actually does not provide any functions that access value types in the mapping. But we can imagine what one might look like: maybe if the deadline of a campaign is extended somehow, an extendDeadline function might look like:

function extendDeadline(uint campaignID, uint256 newDeadline) {
    var campaign = campaigns[campaignId];
    campaign.deadline = newDeadline;

The extendDeadline function would be using the campaignID _KeyType to query the campaigns mapping to find the appropriate CampaignData struct and update its deadline with the newDeadline.

Related Topic