4thのDAY5は「ミニツク 演習 1~3」になります。
前回でProgateでの学習は終了したので、次は実践です。インプットしたら必ずアウトプット(実践)。アウトプットしなければ成長はありません。
演習1
処理自体は作成したものの、実行結果にアドレス的なものが出力されるのと、模範回答と照らし合わせた時に「<<()」という謎のメソッドが出てきてました。 正直「演習1からこんな感じかよ・・・」思ってしまいましたね。 必ずしも模範回答どおりのコードにする必要はありませんが、模範回答がなぜそのようなコードなのかという理由はきちんとおさせておくべきですね。 またそれ意外にも新たに知ったことが出てきたので、備忘録として残しておきます。
<<()メソッドについて
Rubyは演算子はただのメソッドにすぎず、オーバーライド可能というびっくりな仕様があるようです。
僕が参考にさせてもらったRuby | 再定義できる演算子 で組み込み演算子風のメソッドを定義する #rubyにも書かれていますが、普通に記述する演算の式はメソッドを呼び出す構文のシンタックスシューガー(元々の分を簡易的に記述できるようにしたもの)とのことです。
このことから「<<()」メソッドは配列の最後尾に追加するというメソッド(演算子)をオーバーライドしているということになります。 僕はこのメソッドを普通のメソッド名にしてしまいましたが、「配列の最後尾に要素を追加する」というのも元々「<<」の機能なので、それをオーバーライドして作成すべきということなんでしょうね。
joinメソッド(Arrayクラス)
配列に格納された値を出力するためにeach文を使用して1要素ずつputsしましたが、模範回答では配列を管理するクラスである「Arrayクラス」の「joinメソッド」が使用されていました。
# 自分のコード
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メソッドの構文は以下のとおりで、引数に区切り文字を指定することで配列の要素を指定された区切り文字を間に挟み連結してくれます。
# 構文
配列名.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
# 自分のコード
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メソッドはハッシュを配列に変換して返します。
# 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とドットインストールで学習した内容のまとめ。
https://jyu2log.com/ruby-syntax-note/
とりあえず考えても分からなくても悲観することなく、模範回答を見てみて分からないところはググってコードの意味や何故そうしているか?というところを考えれたら良いと思います。
分からないからといって投げ出してしまうと成長はありませんから。


 
			 
			 
			 
			 
			 
			 
			 
			
コメント
コメント一覧 (1件)
[…] DAY5で行った演習1〜3(個人的には特に演習1)で知らないことばっかり出てきたので、覚悟してのぞみます。 […]