恥ずかしい話ですが、つい最近まで「綺麗なコードを書け」と言われると、条件反射的に「エラーがなけりゃいいじゃん。」と思っていました・・・。
しかし、リファクタリングという言葉を理解しながら、いくつかの記法やメソッドに触れていくうちに、美しいコードを美しいと思えるようになってきた(すこし大袈裟)ので、基本的なリファクタリングの事例を紹介したいと思います。
###今回設定するインプットとアウトプット
1から5までの連続する配列の合計を出力せよ。(答えは15)
これをいかに綺麗に記述して導き出すかに挑戦してみたいと思います。
####その1:ザ・ごり押し
p 1 + 2 + 3 + 4 + 5
…プログラムというか電卓?レベルの一番シンプルな記述。当然、1~100までの数字の合計を求める場合等に対応できないのでボツ。
拡張性を持たせていきたい。
####その2:配列とeach文を使う
numbers = [1,2,3,4,5]
sum = 0 #変数sumに0を代入
numbers.each do |n|
sum += n #変数sumにブロック変数nを繰り返し足しこむ
end
p sum
each文で一番最初に習うコードかもしれない。プログラミングだけんども、「配列の要素を1,2,3…と書くのが面倒」、「each文まわりが数行にわたっててコンパクトにしたい」という気持ちが湧いてくる。
####その3:範囲オブジェクトと{}のブロック記法でシンプルに
numbers = (1..5) #範囲オブジェクトの作成。1~5までの値が連続する配列を意味する。
sum = 0
numbers.each {|n| sum += n } #{}のブロック記法で1行に収める。
p sum
__(最初の値..最後の値)で、値の範囲を表すことができる。
※範囲オブジェクトは、Rangeクラスのオブジェクト。
※ちなみに、(最初の値...最後の値)と書くと、最後の値を含まない。ドット.の数に注意
また、each文の__do・・・end__までの間を、{}__で代わりに囲むこともできる。
※__do・・・end__までを「ブロック」と呼び、取り出した要素を扱う「作業部屋」のような役割。
だいぶスッキリしました。けど、もう一息!
####その4:eachの代わりにinjectメソッドを使う
numbers = (1..5)
p sum = numbers.inject(0) {|n, s| n + s}
#injectメソッドは下記の流れで動く。
#メソッドの第1引数が、ブロックの第1引数に入る。
#ブロックの第2引数には、配列の各要素が順番に入る。
#ブロックの戻り値が、ブロックの第1引数に引き継がれる。
#繰り返し処理が終わると、ブロックの戻り値がinjectメソッドの戻り値となる。
injectメソッドを使うことで、引数を複数扱うことができ、2行に収めることができた。
今後は、良著と聞いた「リーダブルコード」も読み進めながら、胸を張って見せられる綺麗なコードを書けるよう頑張っていきます。
「こういう風に書いた方がもっと簡潔だよ。」という意見等ありましたら、ぜひ教えてください!