🤔

いつmemoryを使い、いつcalldataを使うのか?【Solidity】

2022/09/13に公開1

memoryとcalldataの使い分け

コーディングしてると良く使い分けに悩むmemorycalldataをまとめてみました

Solidityの5つの記録領域

Solidityは記憶領域が5つあり、これらを用いてデータのやり取りを行う。

  • memory
  • storage
  • calldata
  • stack
  • returndata

memoryとcalldataの公式ドキュメント

memory

memory から memory への割り当てでは参照のみ作られます。つまり、memory変数への変化は同じデータを参照している他のmemory変数からも可視であるということです。

calldata

Calldataは外部コントラクトのファンクションの参照型のパラメータとして要求される場合にのみ有効です。Calldataは修正不可で、ファンクションの引数が保存される非永続的なエリアで、基本的にはmemoryの様に振舞います。

memoryとcalldataの自分的な理解

memory

  • 一時的な保存領域
  • 関数の引数と関数内の変数に割り当て可能
  • 指定できる型に条件なし
  • ミュータブル(上書き可能)

calldata

  • 一時的な保存領域
  • 関数の引数のみに割り当て可能
  • 指定できる型は配列、構造体、マッピング
  • イミュータブル(上書き不可)

memoryとcalldataの具体的なコーディング

memory

function test (uint256[] memory input) public returns (uint256 memory) {
	input[0] = 1; //memoryなので変更可能
	return input;
}

calldata

function test (uint256[] calldata input) public returns (uint256 calldata) {
	//calldataなので変更不可
	return input;
}

現状の自分の使い分け

  • 構造体、配列、マッピング変数で関数内で書き換えが起こらない場合はcalldata
  • 構造体、配列、マッピング変数で関数内で書き換えが必要な場合はmemory
  • それ以外は全てmemory

参考文献

When should I use calldata and when should I use memory?
https://ethereum.stackexchange.com/questions/74442/when-should-i-use-calldata-and-when-should-i-use-memory

Solidityの公式ドキュメント
https://solidity-jp.readthedocs.io/ja/latest/types.html?highlight=calldata#data-location

Discussion

iharuyaiharuya

function test (uint256[] calldata input) public returns (uint256 calldata)

について0.8.17の公式ドキュメントを見てみると、0.6.9からcalldataはexternal以外でも使えるようになったとのことですが、publicにしてもそれをコントラクト内の他の関数から呼んだらmemory->calldataのimplicit conversionでエラーがでるのでexternalにしておくべきだと思いました。

ついでに、返り値の型をuint256[]にするのと、pure修飾子をつけるといいと思います。