Как работает отображение в Solidity?

Я подробно рассмотрел пример краудфандинга, где столкнулся со следующим:

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;
}

Что здесь происходит на самом деле?

Почему мы использовали картирование? Как это помогает нам? Я не мог понять его работу и, следовательно, не мог его использовать.

Ответы (3)

Анатомия отображения

Отображение используется для структурирования типов значений, таких как логические значения, целые числа, адреса и структуры. Он состоит из двух основных частей: a _KeyTypeи a _ValueType; они появляются в следующем синтаксисе:

mapping (_KeyType => _ValueType) mapName

В примере контракта, представленном выше,

mapping (uint256 => CampaignData) campaigns

это и это . uint256_ Обратите внимание на то, что , , является структурой._KeyTypeCampaignData_ValueType_ValueTypeCampaignData

Сопоставление типов значений с типами ключей

Подумайте о _KeyTypeключе, который вы будете передавать через функцию, чтобы вернуть желаемое значение, или _ValueType. По умолчанию сопоставление изначально пусто, поэтому _KeyTypeсначала необходимо сопоставить новый a с файлом _ValueType.

Функция контракта в примере startобрабатывает 3 основных процесса: (1) присваивание _KeyTypeновой _ValueType CampaignDataструктуре; (2) заполнение новой CampaignDataструктуры значениями переменных; и (3) получение нового _KeyType nextCampaignID, чтобы он был готов к следующему вызову функции примера контракта start. Эти сегменты функции можно разделить следующим образом:

(1) придание _KeyTypeновой _ValueType CampaignDataструктуре:

    var campaign = campaigns[nextCampaignId];

В этой строке nextCampaignIdотображается как _KeyType, а новая campaignструктура — как _ValueType.

(2) заполнение новой CampaignDataструктуры значениями переменных:

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

(3) получение нового _KeyType nextCampaignIDдля следующего вызова функции:

    nextCampaignId ++;

Использование сопоставления здесь полезно, потому что сопоставление может хранить много _KeyTypesдо _ValueTypes- в этом случае, если есть много кампаний, происходящих одновременно, каждая из них может иметь свой собственный идентификатор кампании. Каждая кампания, имеющая собственный идентификатор, имеет большое значение при вызове CampaignData в будущих функциях.

Доступ к типам значений из сопоставления с ключевыми типами

Этот пример контракта на самом деле не предоставляет никаких функций, которые обращаются к типам значений в сопоставлении. Но мы можем представить, как это может выглядеть: может быть, если срок кампании каким-то образом продлить, extendDeadlineфункция может выглядеть так:

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

Функция extendDeadlineбудет использовать campaignID _KeyTypeдля запроса campaignsсопоставления, чтобы найти соответствующую CampaignDataструктуру и обновить ее deadlineс помощью newDeadline.

Так что это просто массив (без доступа по индексу) объектов javascript. Этот ответ вроде хорош, но когда я вижу его в коде, я все еще путаюсь.

Отображение — это набор пар ключ-значение. Итак, если вы пришли из мира JavaScript, вы можете думать о отображении как о чем-то очень похожем на объект.

Исходя из Ruby, они похожи на хэши, а если вы пришли из Python, они похожи на словари.

Главное, что нужно помнить о сопоставлении, это то, что все ключи должны быть одного типа, и все значения также должны быть одного типа.

Все ключи должны быть одного типа, мы можем назначить отображения следующим образом:

mapping(string => string)

Мы говорим сопоставление и указываем тип ключа, который мы хотим использовать, маленькую стрелку, а затем тип значения, которое мы хотим использовать.

Вот пример отображения с ключом типа int и bool:

mapping(int => bool)

Отображения чаще всего используются для хранения коллекций данных.

  mapping(uint256 => CampaignData) campaigns;

Приведенное выше отображение говорит, что ключи будут «uint», а значения будут структурой «CampaignData» и пометят переменную «кампаниями». «CampaignData» можно было бы хранить в массиве, но перебор массива стоил бы слишком много газа. В Эфириуме каждая операция стоит вам денег, и представьте, что у вас хранятся тысячи кампаний, и вам нужно искать каждую кампанию, это будет стоить огромного количества газа. Вместо этого используется сопоставление, потому что сопоставление имеет постоянный поиск по времени.

Отображение в Solidity похоже на отображение в javascript, но есть некоторые отличия:

1- В солидности ключи не хранятся. Только значение, хранящееся по адресу памяти состояния, вычисляется путем хеширования самого ключа. В javascript мы могли бы получить все «ключи» в массив с расширением Object.keys(objectName).

2- Значения в отображении твердости не повторяются. Мы не можем зациклиться. Отображение подходит только для поиска одного значения.

3- В твердости существуют все ценности. В javascript, если мы попытаемся получить доступ к несуществующему ключу, objectName['keyThatDoesNotExist']мы получим undefined. Но в солидности мы получаем значение по умолчанию на основе значений. Если все значения являются строками, значением по умолчанию является пустая строка '', если все значения являются целыми числами, значением по умолчанию является 0, если все значения являются логическими значениями, значением по умолчанию является false.