LoginSignup
8
5

More than 5 years have passed since last update.

Solidityの配列n面相、ほかハマりどころ

Posted at
pragma solidity ^0.4.23; // この文書の対象バージョン

はじめに

Ethereum上のコントラクトを書こうとしてSolidityを使ってみましたが、いろいろハマってしまいました。特に、配列の扱いについて複雑な面が多いと感じました。

文法の違い

Solidityは概ねC言語やJavaScript的な文法となっていますが、微妙なところで違うので、同じ感覚で書いていると思わぬところでエラーとなってしまいます。

変数宣言

変数宣言を複数いっぺんに行うことが、現行のSolidityでは行えません。「コントラクトの読みやすさに寄与するものではない」ということで、Issueも閉じられています。1つずつ書くほかありません。

uint a, b; // エラー

uint a;
uint b;

関数の修飾子

他の言語と同じ感覚でpublic functionと書いてみたところ、これもエラーとなりました。Solidityの関数記法は、function(引数) 修飾子 returning(返り値)のように順番が決まっていて、そのとおりに書くしかありません。

storage変数とmemory変数

Ethereumがブロックチェーンの仕組みなので、変数にもコントラクトを超えて永続するstorage変数と、1回の実行で役割を終えるmemory変数があります。状況によってデフォルトでどちらになるかが決まっていますが、

  • 関数外の状態変数…storage固定
  • 関数の引数…デフォルトでmemory
  • ローカル変数…デフォルトでstorage

というようになっています。ただ、煩雑ですので、状態変数以外は常に明示したほうがいいかもしれません。そして、それぞれの間で代入を行った場合、以下のような動作になります。配列などの参照型といっても、コピーされる場面が多々あるのは要注意です。

from\to 状態 memory storage
状態変数 コピー コピー 参照設定
memory変数 コピー コピー※
ローカルのstorage変数 コピー コピー※ 参照のコピー※

☆:値型ならコピー、参照型(配列・struct)なら参照のコピー
※:事前に参照設定をしていなければ動かない。

配列の複雑さ

さらに、配列では特有の注意点がいくつもあります。

添字の型

Solidityでは、配列の要素は0から始まり、「負の値でアクセスすると末尾から数える」というような機能がないこともあって、添字の型はuintとなっています。C言語的にfor(int i = 0; i < arr.length;++i){ arr[i] }のように書いてしまうと、intuintに暗黙の変換ができないので、コンパイル時点でエラーとなります。ループカウンタはuintで宣言しましょう。

固定長配列と動的長さの配列1

Solidityの配列には、固定長のものと動的長さのものがありますが、動的長さの配列はmemorystorageで挙動が異なります。

  • 固定長配列…int[3] arr;のように、宣言時に個数を決め打つ。配列リテラルも固定長配列扱い。
  • memoryの動的長さの配列…int[] memory arr = new int[](5);のように、newで長さを決める。一度newしたあとには、長さを変更できない
  • storageの可変長配列…デフォルトでは要素0個の配列。.push.lengthの操作で長さを変更可能。

なお、現行のSolidityでは、動的長さの配列に(配列リテラルを含め)固定長配列を代入できないので、「最初にリテラルを追加してから.pushしていく」ようなことは行なえません。また、memory配列は後から長さを変更できないので、「余分目に確保しておく」あるいは「必要な長さを事前に算出する」ような操作が必要です。

ハッシュテーブル(mapping

連想配列的に使えるmappingですが、中身はハッシュテーブルになっていて2、元のキーの値は記憶していません(いくつ入っているか知ることも不可能です)。また、事前に設定していなかったキーで取得しようとした場合、ゼロクリアされた値が得られます。storage専用です。

脚注


  1. memoryの方の挙動が「可変長」とはいいがたいので、こうしています。 

  2. ハッシュ値は256ビットのKeccakなので、ガス代を現実的に支払える範囲内であれば、キーの衝突は気にしなくていいでしょう。 

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5