day9. Solidity基本文法 – 参照型・マッピング型 – 

参照型とは、値そのものではなく、その値が格納されているメモリ位置を指す型です。値型では変数に直接データの値が格納されるのに対して、変数には格納されている位置への参照のみが保存されています。 参照型は、データのメモリ上の位置を保持するため、データの大きさに関係なくメモリの使用を最適化することができます。 マッピング型は、キーと値のペアを格納するデータ構造です。

参照型とは、値そのものではなく、その値が格納されているメモリ位置を指す型です。値型では変数に直接データの値が格納されるのに対して、変数には格納されている位置への参照のみが保存されています。
参照型は、データのメモリ上の位置を保持するため、データの大きさに関係なくメモリの使用を最適化することができます。
マッピング型は、キーと値のペアを格納するデータ構造です。

TOC

配列型

array(配列型)は、同じ型の要素を連続して格納するデータ構造です。Solidityのarrayには固定長と可変長の2種類があります。可変長arrayは要素の追加や削除が可能で、固定長arrayは要素数が固定されています。

次の例では、fruitsは可変長の配列、fixedNumbersは固定長の配列です。配列は、push()pop()という関数で要素を追加したり、削除したりすることができます。

Solidity
string[] fruits = ["banana", "apple", "strawberry"]; // 可変長
uint[3] fixedNumbers = [1, 2, 3]; // 固定長

function processSomething() {
  fruits.pop(); // popにより、最後に追加された要素が削除される
  fruits.push("peach"); // 可変長は要素を追加することができる
  uint length = fruits.length; // lengthにより要素の数が取得できる
  uint secondElement = fixedNumbers[1]; // 配列[i]でi番目の要素が取得できる
}

構造体

struct(構造体)は複数の異なる型の変数をまとめて管理するために使用されます。structは独自のデータ型を定義することができ、1つの変数で複数の値を扱えるようになります。

次の例では、複数の属性情報を持つ人物の情報をまとめて管理するために、Personというstruct型を定義しています。Personは、namebalance(残高)という異なるデータ型である2つの変数を持っており、これはメンバ変数と呼ばれます。
Person型の変数の例として、onePersonanotherPersonの2つの変数が定義されていますが、それぞれ初期化方法が異なる点に注意しましょう(いずれも有効な初期化方法です)。

Solidity
struct Person {
  string name;
  uint256 balance;
}

Person onePerson = Person("Tanaka", 1e18); // 1e18 = 1000000000000000000 (0が18個)
Person anotherPerson;

function processSomething() {
  anotherPerson.name = "Sato";
  anotherPerson.balance = 2e18;
}

マッピング型

mapping(マッピング型)は、キーと値のペアを格納するデータ構造です。キーを指定することで速やかに値を検索(取得)することができます(データベースのテーブルのようなイメージで、キーはインデックスをイメージすると分かりやすいです)。

次の例のaddressToPersonは、address型とPerson型(前述のstructの例)を紐付けるマッピング型の変数です。アドレスと人の情報を紐づけて保存するために使う変数です。
6, 7行目の記述によって、mappingに紐づけが記録されます。

Solidity
mapping(address => Person) addressToPerson;
address oneAddress = 0x551af3f6A226a62BCb27f08B42401bd5629f2E44;
address anotherAddress = 0x0a011ABbCc1Ba8f82eF2c7490f8FD91cb35dBF62;

function processSomething() {
  addressToPerson[oneAddress] = onePerson;
  addressToPerson[anotherAddress] = anotherPerson;
}

データ配置場所

“data location”(データ配置場所)は、配列、構造体などの参照型のデータについて、保存する場所を明示するための記述です。保存場所としては、storage, memory, calldataの3つがあります。

変数を定義する際には、上記のいづれかを意識する必要があります。利用するデータ配置場所によって、ガス代も異なり、高い順に、storage > memory > calldata となります(永続的にデータを保存するstorageが最もコストが高い)。つまり、変数定義においては、ガス代を意識して定義する必要があるということになります。

※ EVMが管理している(アクセスできる)領域という意味では他にもスタック(関数実行の際に利用される一時領域)、ソースコード内やログ領域があります。例えば、後の章で記載するイベントはログ領域に保存されます。

storage

storageは永続的なデータの保存場所であり、スマートコントラクトのストレージ領域に格納されます。storageはブロックチェーン上で状態を保持し、トランザクション間でデータの永続性が確保されます(他の2つと違うのが永続性がある点です)。変数がstorageに格納されている場合、その値はコントラクトの実行ごとに保持されます。

次の例では、PersonStorageというコントラクトの中にaddressToPersonというマッピング変数が定義されています。このaddressToPersonstorageです。

Solidity
contract PersonStorage {
  ...
  mapping(address => Person) addressToPerson;
  ...
}

memory

memoryは一時的なデータの保存場所であり、関数の実行中に使用されます。memoryは関数の実行が終了すると破棄され、データは消失します。memoryは動的に割り当てられたデータや一時的な変数、関数のローカル変数など、実行時に必要なデータを保持するために使用されます。

次の例では、関数の引数(後述)として、numbersという配列を定義していますが、これは関数内だけで使われる想定なので、memoryが適切です。memoryなので、値の変更等も必要であれば可能です。

Solidity
contract PersonStorage {
  ...
  function sumUp(uint[] memory numbers) {
    uint sum = 0;
    for (uint i = 0; i < numbers.length; i++) {
      sum += numbers[i];
    }
    ...
  }
}

calldata

calldataは読み取り専用のデータ領域で、外部からスマートコントラクトに渡される引数や、外部からのトランザクションデータがcalldata内に格納されます。calldata内のデータは変更できません。

次の例では、引数にuserAddress(ユーザーのアドレス)を定義し、アドレスから該当のユーザーの残高を取得し、それをbalanceというmemory型の変数に入れています。

Solidity
contract PersonStorage {
  ...
  function getBalanceOf(address[] calldata addressArray) {
    uint256 sum = 0;
    // addressArray[0] = 0x551af3f6A226a62BCb27f08B42401bd5629f2E44; // 読み取り専用なのでこれはダメ
    for (uint i = 0; i < addressArray.length; i++) {
      sum += addressToPerson[addressArray[i]].balance;
    }
    ...
  }
}

ご意見をお聞かせください!

web3チュートリアルシリーズについてのご意見を是非お聞かせください。

この記事、または、web3チュートリアル全体について、是非、あなたのご意見をお聞かせください。
アンケートはこちらからご回答いただけます。

無料相談承ります

ITの専門家が無料相談を受け付けます。web3以外のテーマでもOKです。

オンラインでの無料相談を承っています。ご希望の方は、お問い合わせフォームよりご連絡ください。
ITの専門家があなたのご質問にお答えいたします。

Let's share this post !

Author of this article

After joining IBM in 2004, the author gained extensive experience in developing and maintaining distributed systems, primarily web-based, as an engineer and PM. Later, he founded his own company, designing and developing mobile applications and backend services. He is currently leading a Tech team at a venture company specializing in robo-advisory.

Comments

To comment

CAPTCHA


TOC