🎃

Solidity初心者のCryptoZombiesまとめ(中級編チャプター2)

2022/08/26に公開

はじめに

前回のチャプター

チャプター2で学べること

アクセス修飾子やストレージ、継承など。

アドレス

  • アカウントの識別子のこと。銀行口座番号のようなもの。

マッピング

  • データの保管と参照のためのキーバリューストア
// accountBalanceというマッピング。キーはaddress、バリュー(値)はuint
mapping (address => uint) public accountBalance;

// userIdToNameというマッピング。キーはuint、バリュー(値)string
mapping (uint => string) userIdToName;

msg.sender

  • 全ての関数で利用できるグローバル変数
  • 関数を呼び出したユーザー(またはスマートコントラクト)のaddressを参照できる
mapping (address => uint) favoriteNumber;

function setMyNumber(uint _myNumber) public {
  // msg.sender下に_myNumberを格納
  favoriteNumber[msg.sender] = _myNumber;
}

function whatIsMyNumber() public view returns (uint) {
  // 送信者のアドレスに格納されている値を受け取る
  return favoriteNumber[msg.sender];
}

require

  • ある条件を満たさない場合はエラーを投げて実行を止める
function sayHiToVitalik(string _name) public returns (string) {
  // まず_nameとVitalikを比較、真でなければエラーで終了
  require(keccak256(_name) == keccak256("Vitalik"));
  // 真ならば、関数を処理する
  return "Hi!";
}

継承

// 継承元
contract Doge {
  function catchphrase() public returns (string) {
    return "So Wow CryptoDoge";
  }
}

// 継承先
contract BabyDoge is Doge {
  function anotherCatchphrase() public returns (string) {
    return "Such Moon BabyDoge";
  }
}

import

import "./someothercontract.sol";
contract newContract is SomeOtherContract {
}

storageとmemory

  • 変数やデータの格納場所のこと

storage

  • Storage はブロックチェーン上に永久に格納される変数
  • 状態変数の場合はデフォルトで storageに格納される
// 以下はエラーになる
Sandwich mySandwich = sandwiches[_index];

// 以下のように書く
Sandwich storage mySandwich = sandwiches[_index];
mySandwich.status = "Eaten!";

memory

  • 一時的な変数で、外部関数をコントラクトに呼び出す際に消去される
  • 関数内で宣言された変数はデフォルトで、memoryに格納される
Sandwich memory anotherSandwich = sandwiches[_index + 1];
anotherSandwich.status = "Eaten!";

アクセス修飾子

  • 関数、変数につけることができるアクセス制限を可能にする
  • 明示的に権限を設定していない場合、デフォルトでpublicとなる

private

  • 定義されたコントラク内からのみ呼び出し可能
呼び出し可否
コントラクト内部からの呼び出し
コントラクト内部からの呼び出し ×
継承先からの呼び出し ×

Internal

  • そのコントラクトと、このコントラクトを継承したコントラクからのみ呼び出し可能
  • privateとの違いは、コントラクトから継承したコントラクトにもアクセスできること
呼び出し可否
コントラクト内部からの呼び出し
コントラクト内部からの呼び出し ×
継承先からの呼び出し

public

  • 継承したコントラクト、また外部から呼び出し可能
  • publicな関数を外部から呼ぶと、引数の値を一度メモリに保存される
呼び出し可否
コントラクト内部からの呼び出し
コントラクト内部からの呼び出し
継承先からの呼び出し

external

  • コントラクトの外からのみ呼び出し可能
  • publicとの違いは、引数で渡された値をメモリに保存されない(publiよりガス代が安い)
呼び出し可否
コントラクト内部からの呼び出し ×
コントラクト外部からの呼び出し
継承先からの呼び出し ×

interface

  • ブロックチェーン上の他人のコントラクトとやりとりを可能にする
  • 関数宣言の終わりにセミコロンを使っていて、それでインターフェースだと判別する
// 他人のコントラクト
contract LuckyNumber {
  mapping(address => uint) numbers;
  function setNum(uint _num) public {
    numbers[msg.sender] = _num;
  }
  function getNum(address _myAddress) public view returns (uint) {
    return numbers[_myAddress];
  }
}

// インターフェースの定義
contract NumberInterface {
  function getNum(address _myAddress) public view returns (uint);
}

// 自分のコントラクト
contract MyContract {
  address NumberInterfaceAddress = 0xab38...; 
  NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
  function someFunction() public {
    // コントラクトからgetNumを呼び出す
    uint num = numberContract.getNum(msg.sender);
  }
}

複数の戻り値を返却する

  • solidityでは複数の戻り値を返すことができる。また、一つの値だけを取得することも可能
function multipleReturns() internal returns(uint a, uint b, uint c) {
  return (1, 2, 3);
}

function processMultipleReturns() external {
  uint a;
  uint b;
  uint c;
  (a, b, c) = multipleReturns();
}

// 一つの値を取得する場合は、以下のように取得する
function getLastReturnValue() external {
  uint c;
  // 他のフィールドは空欄でも構わないぞ:
  (,,c) = multipleReturns();
}

チャプター2のまとめ

アクセス修飾子の範囲などについての明確な違いまで理解できた。
実際の実装ではガス代の考慮まで行う必要があるため、メモリやストレージ、アクセス修飾子について、正しく理解しておく必要があると感じた。

次のチャプターはこちら

Discussion