グローバル変数の問題点メモ
これ is 何?
よくグローバル変数は良くないと聞くがなぜそれがダメなのかの具体例
経緯
最近、バイトで「この書き方はクソコードだよ」とふんわりと教えてもらったので。
本題
よくグローバル変数はヤバいと聞く。結論から言うと、関数と関数の関係が密になりやすいからである。例えば
filename = "hoge.txt" function init_file() local time = tostring(os.date("_%H%M%S")) filename = "hoge"..time..".txt" local f = io.open(filename, "w") if f == nil then io.stderr:write("failed open file") return nil else f:write("header hoge\n") return f end end function write_to_file(file, mes) file:write(mes.."\n") end function close_file(file) file:write("close file\n") file:flush() local ret = file:close() if ret == nil then local ret = false end return ret end function execute_cat_file() local ret = os.execute("cat "..filename) if ret == nil then local ret = false end return ret end
こんなLuaコードを書いたとする。一見問題なさそう、むしろinit_file()したらグローバル変数のfilenameに格納されて、他の関数にfilenameを入れることなく使えて楽やん。と、思ってしまう(少なくとも自分は思っていた)
が、このコードには2点問題がある。
- init_file()しないと他の関数は使えない点。例えば、execute_cat_file()したいだけなのにわざわざinit_file()しないとダメ
- 他のfilenameが使えない。例えば、hoge_100001.txtを生成した後にhoge_100010.txtをinit_file()で生成した場合、hoge_100001.txtは上書きされてしまうので扱うことができなくなる(closeしてないやんっていう問題もあるが)
つまり、最初に話した通り密な関係になってしまう。じゃあどうすればええねんっていうと、
- グローバル変数削除
- init_file()内でファイルを開く処理を削除。
- write_to_file()以外の全ての関数の引数にfilenameを追加する。
以上の3点である。グローバル変数を引数にすることで各関数を疎の関係にする。
外部で生成したいファイルの名前を生成してもらうことになるが、こっちの方が使い勝手が良い。
まとめ
グローバル変数使った時は無意識に密な関係になっていてアレなコードになっている可能性がある。引数で使えるようにして疎な関係にしよう。