0. 前置き
タイトルの「変数は一度だけ書き込む」というのは、リーダブルコードの9.3章のタイトルから抜粋してます。この内容から、自分なりのまとめや解釈を書いていこうと思います。
最近、Flutterメインなので、サンプルなどはdart言語を用いて書いてますので、ご了承ください。
1. 一度だけ書き込める変数
一度だけ書き込める変数にどんなものがあるか。大きく2つあるかなと思います。
1.1. 定数(const)
わかりやすいのが定数ですね。プログラム内にデータを埋め込んじゃいます。
void main() {
const int maxCount = 10;
maxCount = 20; // Error: Can't assign to the const variable 'maxCount'.
}
上記のサンプルは、 maxCount
という定数を定義しています。その後に、定数に対して書き込む処理を書いてますが、コンパイル時にエラーが返されてますね。
ひとまず、 一度しか書き込めない変数 の出来上がりです。
1.2. 再代入不可(final)
再代入不可といったら、定数もそうなんですが、ここではプログラム内で作成したデータを持つ変数について書きます。
import 'dart:math';
void main() {
final int count = Random().nextInt(10);
count = 20; // Error: Can't assign to the final variable 'count'.
}
上記のサンプルでは、ランダムな数字(0〜9)をプログラム内で作成し、変数に格納しています。その変数に final
をつけることで再代入が不可となります。再代入しようとすると、コンパイル時にサンプルのようなエラーメッセージがしっかりと表示されます。
こちらでも、 一度しか書き込めない変数 が出来上がりました。
1.3. まとめ
一度しか書き込めない変数には、下記の2つがある。
・定数(const)
・再代入不可(final)
2. 実例
一度しか書き込めない変数 はわかったけど、実際どう便利なの?ってところを書きます。
2.1. 再代入し放題パターン
void main() {
//・・・①: 必要な変数を定義
double price = 1000; // 単価
double discount = 0.8; // 割引率
int count = 3; // 購入数
double tax = 1.1; // 税率
price = price * discount; //・・・②: 単価に対して、割引をかける
// なんか、いろんな処理
price = price * count; //・・・③: 購入数をかける
// さらに、いろんな処理
price = price * tax; //・・・④: 税率をかける
// ついでに、いろんな処理
print(price); //・・・⑤: 合計金額を表示
}
上記は、ざっくりとした合計金額を計算するプログラムですね。(細かい指摘はご容赦ください・・・)
一見、問題のない簡単なプログラムに見えます。
実際のプログラムは、 // いろんな処理 のところに何十行、何百行といった処理が入ってくることがあります。(もともと、そんなプログラムはクソだというのは置いといて )
もし、「⑤: 合計金額を表示」で合計金額に誤りがあることがわかったらどうでしょう。
おそらく、 price
に関わっている処理を全て見直すことになると思います。 price
は再代入可能な変数なので、もしかしたら // いろんな処理 のところで、全く想定していなかった値が代入されているかもしれません。さらに、これは他の変数( discount
、 count
、 tax
)にも同様のことが言えます。
そうなると、プログラムのどこに問題があるのか、それを探すのがとてつもなくく大変な作業だと思えるじゃないでしょうか。
2.2. 再代入不可パターン
void main() {
//・・・①: 必要な変数を定義
const double price = 1000; // 単価
const double discount = 0.8; // 割引率
const int count = 3; // 購入数
const double tax = 1.1; // 税率
final discountedPrice = price * discount; //・・・②
// なんか、いろんな処理
final totalPrice = discountedPrice * count; //・・・③
// さらに、いろんな処理
final taxedTotalPrice = totalPrice * tax; //・・・④
// ついでに、いろんな処理
print(taxedTotalPrice); //・・・⑤
}
定義した変数の全てに const と final をつけました。
こうすると、「変数が変なところで変更されているかもしれない」という心配をしなくてよくなります。例え、⑤でバグが発覚したとしても、とても追いやすくなりました。
2.3. まとめ
変数の思わぬ変更から守るために、変数を再代入不可にする(const, finalをつける)
3. 最後に
実例では処理をメインに書きましたが、本当の実例は Price クラスを作ったりして、対応することが多いでしょう。その場合も同じで、Priceクラスのインスタンス化された変数が容易に変更されないよう注意が必要です。
さらに踏み込んだ完全コンストラクタという手法もありますが、ここでは省きます。ぜひ、調べてみてください。