[Solidityのはじめ方] Part8: 演算子・条件分岐・ループ

Solidity

スマートコントラクトのロジックを組み立てるための基礎部品を学びます。

1. 演算子 ✨

Solidityでは、他の多くのプログラミング言語と同様に、様々な演算子を使って計算や比較、論理的な操作を行うことができます。これらの演算子を理解することは、コントラクトの動作を正確に制御するために不可欠です。

算術演算子

数値計算に使用します。

演算子説明例 (a=10, b=3)結果
+加算a + b13
-減算a - b7
*乗算a * b30
/除算(整数除算)a / b3 (小数点以下切り捨て)
%剰余(余り)a % b1
**べき乗a ** b1000
⚠️ 注意: Solidity 0.8.0以降では、算術演算におけるオーバーフロー(計算結果が表現できる最大値を超えること)やアンダーフロー(最小値を下回ること)は自動的に検出され、エラー(revert)を引き起こします。これにより、以前のバージョンで必要だったSafeMathライブラリなどが不要になるケースが増えました。ただし、unchecked ブロックを使用すると、このチェックを意図的に無効化できます(ガス代削減のためなど、特別な理由がある場合のみ推奨)。

比較演算子

二つの値を比較し、結果を真偽値 (bool) で返します。

演算子説明例 (x=5, y=8)結果
==等しいx == yfalse
!=等しくないx != ytrue
<より小さいx < ytrue
>より大きいx > yfalse
<=以下x <= ytrue
>=以上x >= yfalse

論理演算子

真偽値 (bool) を操作します。

演算子説明例 (p=true, q=false)結果
!論理NOT (否定)!pfalse
&&論理AND (かつ)p && qfalse
||論理OR (または)p || qtrue

ビット演算子

整数型のビットレベルでの操作に使用します。ガス効率の良い計算やフラグ管理などで使われることがあります。

  • & (ビットAND)
  • | (ビットOR)
  • ^ (ビットXOR)
  • ~ (ビットNOT)
  • << (左シフト)
  • >> (右シフト)

代入演算子

変数に値を代入します。

  • = (単純代入)
  • +=, -=, *=, /=, %= (算術演算と代入)
  • |=, &=, ^= (ビット演算と代入)
  • <<=, >>= (シフト演算と代入)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract AssignmentOperators {
    uint256 public myNumber = 10;

    function addToNumber(uint256 value) public {
        myNumber += value; // myNumber = myNumber + value; と同じ
    }

    function multiplyNumber(uint256 value) public {
        myNumber *= value; // myNumber = myNumber * value; と同じ
    }
}

三項演算子

条件に基づいて二つの値のどちらかを選択する簡潔な方法です。

condition ? value_if_true : value_if_false

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract TernaryOperator {
    function getLarger(uint256 a, uint256 b) public pure returns (uint256) {
        // a が b より大きい場合は a を、そうでなければ b を返す
        return a > b ? a : b;
    }
}

2. 条件分岐 🧭

プログラムの流れを特定の条件に基づいて変えるために、条件分岐を使用します。Solidityでは主に if, else if, else 文が使われます。

if 文

指定した条件が真 (true) の場合に、特定のコードブロックを実行します。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract IfStatement {
    function checkValue(uint256 value) public pure returns (string memory) {
        if (value > 100) {
            return "Value is greater than 100";
        }
        // 条件が偽の場合、この部分は実行されない
        return "Value is 100 or less"; // ifの外に到達した場合の処理
    }
}

if-else 文

条件が真の場合と偽の場合で、異なるコードブロックを実行します。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract IfElseStatement {
    mapping(address => uint256) public balances;

    function checkBalance(uint256 amount) public view returns (string memory) {
        if (balances[msg.sender] >= amount) {
            return "Sufficient balance";
        } else {
            return "Insufficient balance";
        }
    }
}

if-else if-else 文

複数の条件を順番にチェックし、最初に真となった条件のコードブロックを実行します。どの条件も真でない場合は、else ブロックが実行されます。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract IfElseIfElseStatement {
    function checkNumber(int256 number) public pure returns (string memory) {
        if (number > 0) {
            return "Positive";
        } else if (number < 0) {
            return "Negative";
        } else {
            return "Zero";
        }
    }
}

前述の三項演算子も、簡単な if-else の代替として利用できます。

3. ループ 🔄

同じ、または類似した処理を複数回繰り返す場合にループを使用します。Solidityでは for, while, do...while ループが利用可能です。

🚨 最重要注意点: ガス消費量!
ループ処理は非常に多くのガスを消費する可能性があります。特に、ループの反復回数がユーザー入力やストレージの状態に依存する場合、予期せずガス上限 (Gas Limit) を超えてしまい、トランザクションが失敗する原因となります。
可能な限り、ループ回数が予測可能で、かつ少ない回数で済むように設計してください。 大量のデータを処理する必要がある場合は、オフチェーンで処理するか、複数回のトランザクションに分割するなどの工夫が必要です。無限ループは絶対に避けてください!

for ループ

指定した回数だけ処理を繰り返すのに適しています。初期化式、条件式、更新式を指定します。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract ForLoop {
    // 指定された回数だけ合計を計算する(ガス消費に注意!)
    function sumUpTo(uint256 n) public pure returns (uint256) {
        uint256 total = 0;
        // iが0から始まり、nより小さい間、iを1ずつ増やしながらループ
        for (uint256 i = 0; i < n; i++) {
            total += i;
            // ループ内の処理が複雑だったり、nが大きいとガスを大量消費
        }
        return total;
    }

    // 配列の要素を処理する(これも配列が大きいとガス高騰)
    function sumArray(uint256[] memory arr) public pure returns (uint256) {
        uint256 total = 0;
        for(uint i = 0; i < arr.length; i++) {
            total += arr[i];
        }
        return total;
    }
}

while ループ

指定した条件が真である間、処理を繰り返します。ループ前に条件が評価されます。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract WhileLoop {
    // 条件が満たされるまで値を減らす(ガス消費に注意!)
    function decreaseUntil(uint256 startValue, uint256 threshold) public pure returns (uint256) {
        uint256 value = startValue;
        // value が threshold より大きい間ループ
        while (value > threshold) {
            value--;
            // 無限ループにならないように注意!
        }
        return value;
    }
}

do...while ループ

while ループと似ていますが、条件の評価がループ本体の実行後に行われる点が異なります。そのため、条件が最初から偽であっても、少なくとも1回はループ本体が実行されます。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract DoWhileLoop {
    // 少なくとも1回処理を実行し、条件が満たされるまで繰り返す(ガス消費に注意!)
    function processAtLeastOnce(uint256 initialValue) public pure returns (uint256) {
        uint256 value = initialValue;
        do {
            // 何らかの処理
            value++;
            // この処理が少なくとも1回実行される
        } while (value < 5); // valueが5未満の間繰り返す
        return value;
    }
}

break と continue

  • break: 現在実行中のループ (for, while, do...while) を即座に終了します。
  • continue: ループ内の残りの処理をスキップし、次の反復(forの場合は更新式、while/do...whileの場合は条件評価)に進みます。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract BreakContinue {
    // 配列内で最初の偶数を見つけるか、合計が10を超えたらループを抜ける
    function findFirstEvenOrStop(uint256[] memory data) public pure returns (uint256 sum) {
        sum = 0;
        for (uint i = 0; i < data.length; i++) {
            if (data[i] % 2 == 0) {
                 // 偶数が見つかったらループ終了
                break;
            }
            if (sum + data[i] > 10) {
                // 合計が10を超える場合は、この要素を加算せずに次の要素へ
                continue;
            }
            sum += data[i];
        }
        // break またはループ終了後にここに到達
        return sum;
    }
}

まとめ 💡

今回は、Solidityにおける演算子、条件分岐 (if/else)、ループ (for/while/do-while) について学びました。これらはスマートコントラクト内でロジックを記述するための基本的な要素です。

  • 演算子: 計算、比較、論理操作の基本。オーバーフロー/アンダーフローに注意(Solidity 0.8以降はデフォルトでチェック)。
  • 条件分岐: if, else if, else でプログラムの流れを制御。
  • ループ: for, while, do...while で繰り返し処理。ガス消費量に細心の注意が必要!

これらの構文を組み合わせることで、より複雑で実用的なスマートコントラクトを作成することができます。次のステップでは、コントラクトの構造や機能についてさらに深く学んでいきましょう!

参考情報 📚

コメント

タイトルとURLをコピーしました