Я подробно рассмотрел пример краудфандинга, где столкнулся со следующим:
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;
}
Что здесь происходит на самом деле?
Почему мы использовали картирование? Как это помогает нам? Я не мог понять его работу и, следовательно, не мог его использовать.
Анатомия отображения
Отображение используется для структурирования типов значений, таких как логические значения, целые числа, адреса и структуры. Он состоит из двух основных частей: a _KeyType
и a _ValueType
; они появляются в следующем синтаксисе:
mapping (_KeyType => _ValueType) mapName
В примере контракта, представленном выше,
mapping (uint256 => CampaignData) campaigns
это и это . uint256
_ Обратите внимание на то, что , , является структурой._KeyType
CampaignData
_ValueType
_ValueType
CampaignData
Сопоставление типов значений с типами ключей
Подумайте о _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, вы можете думать о отображении как о чем-то очень похожем на объект.
Исходя из 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
.
ИнфинитПрайм