4thのDAY5は「ミニツク 演習 1~3」になります。
前回でProgateでの学習は終了したので、次は実践です。インプットしたら必ずアウトプット(実践)。アウトプットしなければ成長はありません。
演習1
処理自体は作成したものの、実行結果にアドレス的なものが出力されるのと、模範回答と照らし合わせた時に「<<()」という謎のメソッドが出てきてました。 正直「演習1からこんな感じかよ・・・」思ってしまいましたね。 必ずしも模範回答どおりのコードにする必要はありませんが、模範回答がなぜそのようなコードなのかという理由はきちんとおさせておくべきですね。 またそれ意外にも新たに知ったことが出てきたので、備忘録として残しておきます。
<<()メソッドについて
Rubyは演算子はただのメソッドにすぎず、オーバーライド可能というびっくりな仕様があるようです。
僕が参考にさせてもらったRuby | 再定義できる演算子 で組み込み演算子風のメソッドを定義する #rubyにも書かれていますが、普通に記述する演算の式はメソッドを呼び出す構文のシンタックスシューガー(元々の分を簡易的に記述できるようにしたもの)とのことです。
このことから「<<()」メソッドは配列の最後尾に追加するというメソッド(演算子)をオーバーライドしているということになります。 僕はこのメソッドを普通のメソッド名にしてしまいましたが、「配列の最後尾に要素を追加する」というのも元々「<<」の機能なので、それをオーバーライドして作成すべきということなんでしょうね。
joinメソッド(Arrayクラス)
配列に格納された値を出力するためにeach文を使用して1要素ずつputsしましたが、模範回答では配列を管理するクラスである「Arrayクラス」の「joinメソッド」が使用されていました。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 自分のコード def to_s puts "Library contents:" @books.each do |book| puts book end end # 模範回答のコード def to_s puts "Library contents:" @books.join("\n") end |
joinメソッドの構文は以下のとおりで、引数に区切り文字を指定することで配列の要素を指定された区切り文字を間に挟み連結してくれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 構文 配列名.join(区切り文字) 例) array = ["値1", "値2", "値3"] puts "-- 配列をそのまま出力 --" puts array puts "-- 配列を:区切りで連結して出力 --" puts array.join(":") # 実行結果 =begin -- 配列をそのまま出力 -- 値1 値2 値3 -- 配列を:区切りで連結して出力 -- 値1:値2:値3 =end |
to_sメソッドについて
to_sメソッドを実行しないのに何故to_sメソッドが実行されるのか?ここが分かりませんでしたが、【Ruby】表示メソッドについて (print, puts, p)により解決しました。
表示メソッド(print、puts、p)は文字列以外のオブジェクトが指定された場合、内部的にそのオブジェクトのto_sメソッドが実行されて出力されます。そしてそのto_sメソッドはオーバーライド可能。
これを利用して該当のオブジェクトにto_sメソッドを用意すれば、表示メソッドを使用した場合に自動的に自分で用意したto_sメソッドが実行されるというわけです。
演習2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 自分のコード def clever_print(word1, word2, word3) word1.each do |word| print "#{word} " end print "#{word2} " word3.each do |key, word| print "#{key} #{word} " end puts "" end # 模範回答のコード def clever_print(*args) converted = [] args.each { |arg| converted << arg.to_a } puts converted.join(" ") end |
かなりゴリゴリとやっちゃいましたが、まずは実現できることが大事。
というか模範回答のコードは「Stringにはto_aメソッドないよ〜」ってエラーになるんですけどね・・・。
演習2での新登場ポイントは「可変長引数」と「to_aメソッド」です。
可変長引数
引数に「*」を指定することで、引数の数を可変にできます。この場合引数は配列となります。
また引数に「**」を指定するとオプション引数となり、引数の数を可変でハッシュで受け取ることができるようになります。
これは便利ですね。
後々仕様が変更になる可能性があるメソッドの引数とか全部この可変長引数かオプション引数にしてしまいそうです。
to_aメソッド(Arrayクラス)
Arrayクラスのto_aメソッドはレシーバー自体を返します。
またHashクラスのto_aメソッドはハッシュを配列に変換して返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# Arrayクラスのto_aメソッドの構文 配列.to_a # Hashクラスのto_aメソッドの構文 ハッシュ.to_a # 例 array = ["値1", "値2", "値3"] hash = {:key1 => "値4", :key2 => "値5"} puts "-- そのままputs --" puts array puts hash puts "-- to_aしてputs --" puts array.to_a puts hash.to_a # 実行結果 =begin -- そのままputs -- 値1 値2 値3 {:key1=>"値4", :key2=>"値5"} -- to_aしてputs -- 値1 値2 値3 key1 値4 key2 値5 =end |
今回の演習では引数に配列とハッシュが渡ってくるので、このto_aメソッドを利用して処理を共通化してるんですね。
演習3
演習3は特に目新しいことはなかったので特に問題ありませんでした。
強いて言うなら演習1もそうですが、to_sメソッドでputsで終わると、そのオブジェクトのアドレス?的なものが出力されてしまうっていうところですね。
これはputsのメカニズムをもうちょっと調べる必要がありますが、とりあえず先に進もうと思います。
感想・まとめ
Progateのrubyを完了しただけでは結構厳しいんじゃないかなと思います。
模範回答を見ても「@」とかいきなり出てきて「?????」ってなりますしね。
僕は一旦ドットインストールの「Ruby入門」コースを学習してからトライしましたが、それでも分からないことだらけでしたし。
僕がProgateとドットインストールで学習した内容のまとめ。
とりあえず考えても分からなくても悲観することなく、模範回答を見てみて分からないところはググってコードの意味や何故そうしているか?というところを考えれたら良いと思います。
分からないからといって投げ出してしまうと成長はありませんから。