Язык Solidity: Структуры (Урок 5)
Язык Solidity: Структуры (Урок 5)
Предыдущие уроки:
Язык Solidity: Неllo World (Урок 1)
Язык Solidity: Типы данных (Урок 2)
Язык Solidity: Переменные состояния контракта (Урок 3)
Язык Solidity: Массивы и соответствия (Урок 4)
Структура User
В языках программирования структуры подразумневают отдельные (комплексный) типы данных. Опять же возвращаясь к аналогии с нашим PHP и БД можно сравнить с описанием таблицы, а каждая переменная типа этой структуры - запись в этой таблице. Так же как записи в таблицах могут ссылаться на записи в других таблицах по внешнему ключу, можно определить связи между структурами внутри контракта.Как мы знаем - контракты довольно часто применяются для сбора средств (ICO).
Предлагаю как обычно начать с простых примеров дабы въехать в курс дела :)
Вообще любой программист должен воспринимать структуры без особых затруднений, так как большинство приложений вводят и выводят данные именно в виде данных структур, отформатированными по определенным правилам.
Первым примером будет такой контракт:
pragma solidity ^0.4.0;
contract MyStruct {
struct User {
string name;
uint8 age;
uint256 balance; // тип можно просто uint - псевдоним
}
// ID нового юзера
uint lastUserId;
// Создаем соответствие (массив), где будем держать юзеров
mapping(uint => User) users;
// И как обычно добавляем функции для взаимодействия
// с контрактом
// Добавление юзера
function addUser(string name, uint8 age, uint256 balance) returns (uint thisId) {
thisId = lastUserId++; // увеличиваем счетчик на 1
users[thisId] = User(name, age, balance);
}
}
Теперь в наш контракт можно добавлять пользователей. Например ввод:
{
"string name": "Ivan I",
"uint8 age": "34",
"uint256 balance": "215"
}
То наш вывод функции (ID пользователя) будет такой:
{
"uint256 thisId": "0"
}
здесь у нас не 1, потому что мы используем постинкремент: thisId = lastUserId++
в данном случае сначала выполняется присваивание, а затем переменная увеличивается на 1.
Если мы добавим нового пользователя, например:
{
"string name": "Ivan I",
"uint8 age": "34",
"uint256 balance": "215"
}
то получим соответственно:
{
"uint256 thisId": "1"
}
и так далее.
Работа с балансом пользователя (учебный пример - как в реальности надо разберем позже)
Для работы с балансом, пишем 3 функции: проверка, зачисление и снятие.
Понятное дело, поскольку мы еще не обсуждали контроль доступа, в реальности так никто не делает (поскольку любой может изменять эти данные). Но нам важно понять принцип.
Просмотр текущего баланса
// Просмотр баланса
function getUserBalanceById(uint userId) returns (uint) {
// Проверка корректности ID
if(userId < 0 && userId > lastUserId) return 0;
// Возвращаем баланс
return users[userId].balance;
}
Тут первая строчка проверяет, что такой аккаунт есть в хранилище данных контракта.
Вторая возвращает его. Так как мы используем массив структур - мы передаем в качестве индекса id пользователя, а для извлечения баланса используем точечный синтаксис.
Пополнение баланса
// Пополнение баланса
function addUserAmount(uint userId, uint amount) {
if(userId > 0 && userId <= lastUserId && amount > 0) {
users[userId].balance += amount;
}
}
Теперь например, если мы добавим пользователя с id=1 и балансом 500 токенов, и вызовем эту функцию с параметрами:
{
"uint256 userId": "1",
"uint256 amount": "30"
}
то getUserBalanceById(1)
вернет 530.
Снятие токенов с баланса
Аналогичным образом токены снимаются
// Это совсем неправильная функция
// Просто вычитает c баланса :)
function daj(uint userId, uint many) {
if(userId > 0 && userId <= lastUserId && many > 0) {
users[userId].balance -= many;
// TODO send
}
}
При транзакции с вызовом этой функции баланс пользователя аналогичным как и при пополнении образом уменьшится на значение many.
Полный код контракта MyStruct
pragma solidity ^0.4.0;
contract MyStruct {
struct User {
string name;
uint8 age;
uint256 balance; // тип можно просто uint - псевдоним
}
// ID нового юзера
uint lastUserId;
// Создаем соответствие (массив), где будем держать юзеров
mapping(uint => User) users;
// И как обычно добавляем функции для взаимодействия
// с контрактом
// Добавление юзера
function addUser(string name, uint8 age, uint256 balance) returns (uint thisId) {
thisId = lastUserId++; // увеличиваем счетчик на 1
users[thisId] = User(name, age, balance);
}
// Просмотр баланса
function getUserBalanceById(uint userId) returns (uint) {
// Проверка корректности ID
if(userId < 0 && userId > lastUserId) return 0;
// Возвращаем баланс
return users[userId].balance;
}
// Пополнение баланса
function addUserAmount(uint userId, uint amount) {
if(userId > 0 && userId <= lastUserId && amount > 0) {
users[userId].balance += amount;
}
}
// Это совсем неправильная функция
// Просто вычитает c баланса :)
function daj(uint userId, uint many) {
if(userId > 0 && userId <= lastUserId && many > 0) {
users[userId].balance -= many;
// TODO send
}
}
}