mapping・struct・配列
人ごと・リストのデータをまとめて扱う
これまでの変数は「値段」「累計」のようなひとつの値でした。今回は「人ごとのポイント」「商品のリスト」のような、たくさんの値をまとめて扱う道具を 3 つ覚えます。
mapping = 対応表
mapping(マッピング)は「AにはB」という対応表です。自販機に付けたポイントカードの台帳だと思ってください。「この住所の人は 30 ポイント」「あの住所の人は 10 ポイント」。
mapping(address => uint256) public points;
「住所(address)から整数(uint256)を引ける対応表を points と名づける」という意味です。使うときは points[住所] で読み書きします。
配列 = 順番つきのリスト
配列(はいれつ)は、順番に並べたリストです。メンバーの名簿や商品の陳列棚にあたります。
address[] public members;
「住所を並べたリストを members と名づける」。members.push(x) で末尾に追加できます。
struct = 自分で作るひとまとまり
struct(ストラクト)は、関連する値をひとまとめにした「自分で作る型」です。商品カードのイメージ——1 枚のカードに「名前」と「値段」が書いてある、あれです。
struct Item {
string name;
uint256 price;
}
3つを組み合わせた台帳
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract PointBook {
mapping(address => uint256) public points;
address[] public members;
struct Item {
string name;
uint256 price;
}
Item[] public items;
function addPoint() public {
if (points[msg.sender] == 0) {
members.push(msg.sender);
}
points[msg.sender] += 10;
}
function addItem(string calldata name, uint256 price) public {
items.push(Item(name, price));
}
}
addPoint= 操作した人(msg.sender)に 10 ポイント。if (条件) { }は「条件が成り立つときだけ実行」——初回(0 ポイント)の人だけ名簿に追加しています- なお Lab では操作が全員ぶん同じ代行送信者から届くため(第4回の note 参照)、「人別に分かれる」様子までは体験できません。書き方と意味を覚えましょう
Item[] public items;= 商品カード(struct)を並べた陳列棚。addItem("cola", 120)のように呼ぶと、カードを 1 枚作って棚に足します
データの置き場所(storage / memory / calldata)
第2〜3回で予告した話です。addItem の引数に付いていた calldata は、データの置き場所の指定です。
| 指定 | 置き場所 | イメージ |
|---|---|---|
storage | ブロックチェーン本体 | 自販機に貼った、消えないメモ |
memory | 処理中だけの作業台 | 手に持ったメモ。処理が終わると捨てる |
calldata | 受け取った引数そのまま | 届いた注文書を、書き換えずそのまま読む |
- 状態変数(contract 直下)は自動的に storage です
stringや struct・配列を関数の引数や戻り値にするときだけ、memoryかcalldataを明示するルールがあります(第7回のreturns (string memory)もこれ)。迷ったら「受け取るだけなら calldata、加工するなら memory」uint256やboolのような小さい値には不要です
今回覚えたこと
- mapping = 対応表(
points[住所]で読み書き)/ 配列 = 順番つきリスト(pushで追加)/ struct = 値をひとまとめにした自作の型 - storage / memory / calldata = データの置き場所。string 等を引数・戻り値にするときに明示する
次回は、設計図を引き継いで拡張する継承です。
:::tip Lab でやってみる
PointBook をデプロイして、①addPoint を 2 回実行 ②members に 0 を入れて読むと、名簿の先頭の住所(0x...)が出ます ③その住所をコピーして points に入れて読むと 20 ④addItem に cola と 120 を入れて実行 → items に 0 を入れて読むとカードの中身が見えます。操作方法: コントラクトを動かす
:::