0
0

More than 1 year has passed since last update.

Solidityのmemoryとstorageについての備忘録

Posted at

はじめに

今回はdAppsを練習で実装している際に「storage」と「memory」の扱い方に関して少し戸惑ったので備忘録として残しておきます。

storage

storageはブロックチェーン上に永久に保存される変数。

可変長配列を使用する場合、storageで宣言する必要がある。

関数外で宣言する場合、デフォルトでstorageになっている。

ブロックチェーン上に保存するので、ガス代が高くなる。

memory

コントラクトを実行する場合にのみ保持される変数。

→ブロックチェーン自体に保存されるわけではないため、storageと異なりガス代もかからない。

関数内で宣言する場合にはデフォルトでmemoryになっている。

実装の際に苦労した点

可変長配列を返そうと考えたが、結構苦戦しました。

以下がうまくいかなかったコードです。

function _transferableNFTs(uint256 stage) private view returns (NFTItem[] memory) {
        // return用の変数の宣言
        NFTItem[] list;
        // itemsは状態変数
        for (uint256 index = 0; index < items.length; index++) {
            if (items[index].stage == stage && !items[index].sold) {
                list.push(items[index]);
            }
        }
        return list;
}

memoryであるにもかかわらず配列の宣言の際に初期化を行っていないのでエラーになりました。

そして次に書いたのが以下のコード

function _transferableNFTs(uint256 stage) private view returns (NFTItem[] storage) {
        // return用の変数の宣言
        NFTItem[] storage list;
        // itemsは状態変数
        for (uint256 index = 0; index < items.length; index++) {
            if (items[index].stage == stage && !items[index].sold) {
                list.push(items[index]);
            }
        }
        return list;
}

デフォルトでmemoryになっているので宣言の際に「storage」を追加し、返り値もstorageに変更しました。

しかし、storageを返り値にすることができないためエラーになります。

そして以下のようなコードに変更しました

function _transferableNFTs(uint256 stage) private view returns (NFTItem[] memory) {
        // _transferableNFTCountで事前に配列の数を取得する
        uint256 count = _transferableNFTCount(stage);

        // return用の変数の宣言
        NFTItem[] list = new NFTItem[](count);

        // 新しい配列用のインデックスの宣言
        uint256 currentIndex = 0;

        // itemsは状態変数
        for (uint256 index = 0; index < items.length; index++) {
            if (items[index].stage == stage && !items[index].sold) {
                // pushではなく代入にする
                list[currentIndex] = items[index];
                currentIndex++;
            }
        }
        return list;
}

storageで値を返すことはできないので、memoryの宣言に変更しました。

memoryで宣言する場合、固定長配列になるので事前に配列の長さを定義しておく必要があります。 そのため、宣言前に配列の長さを取得しています。

また、固定長配列の場合は「push」ではなく、代入になるので「currentIndex」というインデックスを別途宣言しています。

これによってmemoryでも実質的に可変長配列を返却できるようになります。

最後に

solidityに可変長配列がなさそうだったので実質的に実装しました。

もし、より効率的な方法があれば教えていただけると幸いです🙇

0
0
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
0
0