複数の条件が絡み合い,ネストが深く読みにくくなってしまったif文のカタマリを一瞬で美しいコードに直す魔法についてです.タプルっていいます.
比較
Before
if (condition0)
if (condition1)
if (condition2)
DoSomethingA();
else
DoSomethingB();
else
if (condition2)
DoSomethingC();
else
DoSomethingD();
else
if (condition1)
if (condition2)
DoSomethingE();
else
DoSomethingF();
else
if (condition2)
DoSomethingG();
else
DoSomethingH();
見るからに気持ち悪いです.condition1
やcondition2
に対する評価が複数箇所に分けて書かれています.残念ながらたまにこういうの見かけます.
After
switch (condition0, condition1, condition2)
{
case (true, true, true): DoSomethingA(); break;
case (true, true, false): DoSomethingB(); break;
case (true, false, true): DoSomethingC(); break;
case (true, false, false): DoSomethingD(); break;
case (false, true, true): DoSomethingE(); break;
case (false, true, false): DoSomethingF(); break;
case (false, false, true): DoSomethingG(); break;
case (false, false, false): DoSomethingH(); break;
}
誰がどう見ても圧倒的にスッキリしたのがわかると思います.ネストが浅いですし,1行目の時点で3つの条件の組み合わせで分岐しようとしていることがわかります.どの条件がどんな状態のときにどこに進むのかが容易に読み取れます.
解説
switch (condition0, condition1, condition2)
は,(condition0, condition1, condition2)
というタプルを作って,それについてswitch
文で分岐していくよ,という意味です.
要するにswitch ((condition0, condition1, condition2))
です.中身にタプルを入れるときはカッコを1つ省略できます.
case (true, true, true):
は,パターンマッチングの位置パターンです.
位置パターンとは,タプルのように分解できる型について,直感的な書き方でマッチングを行える書き方です.見ての通り,1行目で渡したタプルの値が指定した状態になっているかどうかを検査します.
つまり,if (condition0 && condition1 && condition2)
です.
位置パターンというくらいですから,変数の名前を指定しなくても,タプル内の位置をもとに調べることができます.例のようにbool
型の場合は書く量はそんなに変わりませんが,他の型だといちいちis
などの演算子を書かなくて良いので嬉しかったりします.
複数の条件の組み合わせで分岐先を変える場合や,複数のパターンについて網羅的に検査する場合などはこの方法が適しています.
まとめ
例ではswitch
文を使いましたが,当然switch
式やis
演算子でも同じことができます.
このように,複雑な分岐ではパターンマッチングをうまく活用することで可読性を数段上げることができます.綺麗なコードを書いて気持ちよくなりましょう.
参考