チェリー本輪読会の第4週目のエントリーになります。 輪読会の概要については第1週目にまとめています。 期間:2021年06月14日〜2021年06月18日 先週取り掛かったコードをリファクタリングしました。 リファクタリングとは? 外から見た振る舞いは保ったまま、理解や修正が簡単になるように内部のコードを改善することです。 出典:チェリー本 DRY(Don't repeat yourself)の原則に従い行います。 簡単な例。 以下は、引数ひとつに対し一行で記述した例です。 以下は、each文を使い配列で処理しています。 繰り返し書いている箇所をまとめることができ、DRYに従ったリファクタリングと言えます。 下記は、2つ目の要素から3つ分を取り出すコードです。 他にもさまざま取り出し方法があります。 正の値を指定することで配列を取り出すことは問題なく理解できていましたが、負の値を指定した際に取り出す方法の理解が曖昧でした。 改めて見直してみます。 2番目の要素を指定してみます。正の値で指定した動きと同じです。 しかし、取り出しをスタートする地点から右に数えて取得しています。 他に、 引数を指定してあげることで、 最後の要素から順番に指定した分要素を取り出せます。 ちなみに、 Array#concat (Ruby 3.0.0 リファレンスマニュアル) 2つの配列を連結したいときに使うメソッドです。 Excelの、 ramones変数は変更されます。(破壊的) kana変数は変更されません。 ちなみに、 チェリー本では、concatメソッドは破壊的なメソッドなため、思わぬ不具合を与えてしまい兼ねないため、 輪読会恒例になりつつある?笑 「どう発音するか?」問題で盛り上がりました。
イギリス英語、アメリカ英語で違いがあるようです。 CONCATENATE | Cambridge Dictionary による英語での発音 確か、canもイギリスだと「カン」と言っているのを思い出しました。 でもビートルズはキャンって歌っている… せっかくなので調べてみました。なるほど、納得! ビートルズはアメリカ英語で歌っていた(230) - ★ビートルズを誰にでも分かりやすく解説するブログ★ 普段、Rubyのコードを書く際におまじないのように書いている下記のコード。 こちらも疑問に思ったため調べてみました。 Object#freeze (Ruby 3.0.0 リファレンスマニュアル) 凍結されるのはオブジェクトであり、変数ではありません。代入などで変数の指すオブジェクトが変化してしまうことは freeze では防げません。 freeze が防ぐのは、 `破壊的な操作' と呼ばれるもの一般です 文字列リテラルとは? まずはるりまを読む。これが鉄則です。 例えば、先程のconcatメソッド。るりまにはこう書いてあります。 Array#concat (Ruby 3.0.0 リファレンスマニュアル) エクスクラメーションマーク(感嘆符)が付くメソッドは、全て破壊的なメソッドであると思っていましたが、これは勘違いでした。 cocatメソッドのように、 他には、deleteメソッド、clearメソッドも、 以下は、Matzさんのツイートになります。 なるほど。納得できました。 Rubyの「!」つきメソッドは、「!」がついていないメソッドよりもより「危険」という意味です。 上記と同じことがしたい場合、RubyにはSetクラスが用意されています。一般的にはSetクラスを使って集合演算を行います。 class Set (Ruby 3.0.0 リファレンスマニュアル) *splat展開なしの場合。 二次元配列になります。入れ子のデータ構造のことです。 *splat展開ありの場合。 一次元配列で格納できます。 コンピュータプログラムの一部として定義された関数などに渡される引数のうち、あらかじめ数が固定されておらず、任意の数(あるいは事前に定められた範囲の数)を取ることができるものを可変長引数(可変引数、可変個引数)といいいます。チェリー本では、「個数に制限のない引数」と説明されています。 splatは、アスタリスクという意味でもあるようです。 splatの意味・使い方・読み方|英辞郎 on the WEB 個人的にはこのゲームのイメージから英語の意味を紐付けたりしました。 スプラトゥーン2 | Nintendo Switch | 任天堂 配列を \n や\t は文字コードではなくバックスラッシュ記法です。 charsメソッドは、文字列を一文字一文字分解して配列にするメソッドです。 splitメソッドは、引数で渡した区切り文字(今回は 今週2回目の「どう発音するか?」問題。笑 今回はcharsがターゲットになりました。
元々の単語は、character になります。 チャー派とキャラ派。どちらもいい勝負でしたが、結果は....?
ちなみに私はチャー派で、ギタリストのcharに馴染みがあるため、自然とチャーと言ってました。 結論ですが、どっちでもいいらしいです。笑 ですが、こういった小ネタ的な話題で盛り上がれるのも輪読会のひとつの楽しみでもあります。 ちなみに、Paizaが取ったアンケートではチャー派の勝利です!! 「char」をどう読んでいますか? 配列は ちなみに、🍒 はじめに
🍒 輪読会 第4週目まとめ
第4章4.6.4〜第4章4.7.14まで
リファクタリングすべきポイントは「繰り返し処理」部分
irb(main):210:1* def add_second_name(vo, gu, ba, dr)
irb(main):211:1* puts vo.to_s + 'Ramone'
irb(main):212:1* puts gu.to_s + 'Ramone'
irb(main):213:1* puts ba.to_s + 'Ramone'
irb(main):214:1* puts dr.to_s + 'Ramone'
irb(main):215:0> end
=> :add_second_name
irb(main):216:0>
irb(main):217:0> add_second_name('Joey', 'Johnny', 'DeeDee', 'Marky')
JoeyRamone
JohnnyRamone
DeeDeeRamone
MarkyRamone
=> nil
irb(main):218:1* def add_second_name(vo, gu, ba, dr)
irb(main):219:2* [vo, gu, ba, dr].each do |n|
irb(main):220:2* puts n.to_s + 'Ramone'
irb(main):221:1* end
irb(main):222:0> end
=> :add_second_name
irb(main):223:0> add_second_name('Joey', 'Johnny', 'DeeDee', 'Marky')
JoeyRamone
JohnnyRamone
DeeDeeRamone
MarkyRamone
=> ["Joey", "Johnny", "DeeDee", "Marky"]
添字を使った配列の取得方法
配列[位置、取得する長さ]
irb(main):001:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):002:0> ramones[1,3]
=> ["Johnny", "DeeDee", "Marky"]
irb(main):234:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):235:0> ramones[-1]
=> "Marky"
irb(main):236:0> ramones[-3]
=> "Johnny"
irb(main):013:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):014:0> ramones[-3, 2]
=> ["Johnny", "DeeDee"]
last
メソッド配列の最後の要素を取得できます。last
とまったく動きが逆になるfirst
メソッドもあります。irb(main):019:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):020:0> ramones.last
=> "Marky"
irb(main):021:0> ramones.last(2)
=> ["DeeDee", "Marky"]
concatメソッド
CONCATENATE 関数
を思い出しました。
当時、Excelで表計算していた際は大変お世話になった関数です。irb(main):022:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):023:0> kana = ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
=> ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
irb(main):024:0> ramones.concat(kana)
=> ["Joey", "Johnny", "DeeDee", "Marky", "ジョーイ", "ジョニー", "ディーディー", "マーキー"]
irb(main):025:0> ramones
=> ["Joey", "Johnny", "DeeDee", "Marky", "ジョーイ", "ジョニー", "ディーディー", "マーキー"]
irb(main):026:0> kana
=> ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
+
を使っても連結できますが、こちらは非破壊的なので変数は変更されません。irb(main):027:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):028:0> kana = ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
=> ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
irb(main):029:0> ramones + kana
=> ["Joey", "Johnny", "DeeDee", "Marky", "ジョーイ", "ジョニー", "ディーディー", "マーキー"]
irb(main):030:0> ramones
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):031:0> kana
=> ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
+
演算子を使うことを推奨しています。キャット?カット?
# frozen_string_literal: true
# frozen_string_literal: true
frozen_string_literal
はマジックコメントといい、# frozen_string_literal: true
と書くことで、上記のるりまで説明があるように文字列が最初からfreezeされるようです。ただし、文字列リテラルに限られます。破壊的メソッドと非破壊的メソッドの見分け方
!
で終わるメソッド!
で終わるメソッドは、慣習的に「使用する際には注意が必要ですよ」という意味を持っているだけで、必ずしも破壊的メソッドになるわけではありません。ここは注意が必要です。!
が付かなくても破壊的なメソッドは存在します。!
が付かない破壊的メソッドです。
更に exit! のようにレシーバーを破壊しないが(exitより)危険というメソッドもあります。 [https://t.co/JmurlrZIxM](https://t.co/JmurlrZIxM)配列の和集合、差集合、積集合
|
irb(main):001:0> ramones_a = ["Joey", "Johnny"]
=> ["Joey", "Johnny"]
irb(main):002:0> ramones_b = ["DeeDee", "Marky"]
=> ["DeeDee", "Marky"]
irb(main):003:0> ramones_a | ramones_b
=> ["Joey", "Johnny", "DeeDee", "Marky"]
-
irb(main):002:0> ramones_a = ["Joey", "Johnny", "DeeDee"]
=> ["Joey", "Johnny", "DeeDee"]
irb(main):003:0> ramones_b = ["DeeDee", "Marky"]
=> ["DeeDee", "Marky"]
irb(main):004:0> ramones_a - ramones_b
=> ["Joey", "Johnny"]
&
irb(main):001:0> ramones_a = ["Joey", "Johnny", "DeeDee"]
=> ["Joey", "Johnny", "DeeDee"]
irb(main):002:0> ramones_b = ["DeeDee", "Marky"]
=> ["DeeDee", "Marky"]
irb(main):003:0> ramones_a & ramones_b
=> ["DeeDee"]
splat展開
*
を使って1つの引数ではなく、「複数の引数」として配列を展開することができます。irb(main):001:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):002:0> name = []
=> []
irb(main):003:0> name.push(ramones)
=> [["Joey", "Johnny", "DeeDee", "Marky"]]
irb(main):001:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):002:0> name = []
=> []
irb(main):003:0> name.push(*ramones)
=> ["Joey", "Johnny", "DeeDee", "Marky"]
メソッドの可変長引数(variable arguments)
irb(main):004:1* def greeting(names)
irb(main):005:1* "#{names.join('と')}、ハロー!!"
irb(main):006:0> end
=> :greeting
irb(main):007:0> greeting([ "DeeDee", "Marky"])
=> "DeeDeeとMarky、ハロー!!"
irb(main):008:0> greeting( "DeeDee", "Marky")
(irb):4:in `greeting': wrong number of arguments (given 2, expected 1) (ArgumentError)
from (irb):8:in `<main>'
from /Users/shiro/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.6/exe/irb:11:in `<top (required)>'
from /Users/shiro/.rbenv/versions/3.0.0/bin/irb:23:in `load'
from /Users/shiro/.rbenv/versions/3.0.0/bin/irb:23:in `<main>'
*name
とすることで、greeting("DeeDee", "Marky")
としている引数が配列として展開されて、joinメソッドに渡されています。irb(main):009:1* def greeting(*names)
irb(main):010:1* "#{names.join('と')}、ハロー!!"
irb(main):011:0> end
irb(main):012:0*
=> :greeting
irb(main):013:0> greeting("DeeDee", "Marky")
=> "DeeDeeとMarky、ハロー!!"
%記法
[ ]
を使わずに作成できます。%w
%W
を使います。
%w
の場合
irb(main):023:0> ramones = %w(We are Ramones! Hey\nho\nlet's\ngo!!)
=> ["We", "are", "Ramones!", "Hey\\nho\\nlet's\\ngo!!"]
irb(main):024:0> puts ramones
We
are
Ramones!
Hey\nho\nlet's\ngo!!
%W
大文字の場合。
irb(main):021:0> ramones = %W(We are Ramones! Hey\nho\nlet's\ngo!!)
=> ["We", "are", "Ramones!", "Hey\nho\nlet's\ngo!!"]
irb(main):022:0> puts ramones
We
are
Ramones!
Hey
ho
let's
go!!
=> nil
charsメソッド、splitメソッド
irb(main):025:0> 'RAMONES'.chars
=> ["R", "A", "M", "O", "N", "E", "S"]
,
で区切っている)で文字列を配列に分解するメソッドです。irb(main):027:0> 'Joey, Johnny, DeeDee, Marky'.split(',')
=> ["Joey", " Johnny", " DeeDee", " Marky"]
chars の読み方
Array.new
[ ]
で作成することが多いですが、Array.newを使って作成する方法もあります。[ ]
はメソッドでもあります。
下記、同じ意味のコードです。
irb(main):029:0> ramones = [] => [] irb(main):030:0> ramones = Array.new => []
第1引数を渡すと、その個数分の要素が追加されます。初期値はnilです。
第2引数を渡すと、要素が置き換わります。
irb(main):032:0> ramones = Array.new(4) => [nil, nil, nil, nil] irb(main):033:0> ramones = Array.new(4, 'Hey') => ["Hey", "Hey", "Hey", "Hey"]
ミュータブル、イミュータブル
普段馴染みのない単語なので、意味を忘れがちなミュータブル、イミュータブル。
ミュータブルmutable(変更可能な)と、イミュータブルimmutable(変更できない)が「どっちがどっち?」と、ごっちゃになるが、ミュータント・タートルズで覚えることにしました。突然変異。
あと、illiegal < = > ligalの対義語と同じ法則なので、覚えておきたいと思います。
Rubyにはイミュータブルなクラスや値がいくつかあります。基本のデータ型は下記の4つです。
- 数値(Integerクラス、Floatクラス)
- シンボル(Symbolクラス)
- true / false
- nil
言い替えると、Integerクラスやシンボルなどは、そもそも破壊的なメソッドは存在しないということです。
参考書籍
- 伊藤淳一 著/『プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで』/技術評論社/2017年https://gihyo.jp/book/2017/978-4-7741-9397-7
- 五十嵐邦明,松岡浩平 著/『ゼロからわかる Ruby 超入門』/技術評論社/2018年https://gihyo.jp/book/2018/978-4-297-10123-7
- 高橋征義、後藤裕蔵 著/『たのしいRuby第6版』/SBクリエイティブ/2019年https://tanoshiiruby.github.io/6/index.html
- プログラミング言語 Ruby リファレンスマニュアル https://docs.ruby-lang.org/ja/
🍒 まとめ
今週は、配列や繰り返し処理ついて深堀りしていくことができました。
破壊的メソッドについて、深く考えて使うことがなかったのですが、今週の学びを通してプログラムに不具合を与えかねない危険なメソッドであることが理解できました。ミュータブル、イミュータブルも今回しっかり学べ理解することができました。
「同じ値で同一のオブジェクト」なのか?「同じ値で異なるオブジェクト」なのか?意識してプログラムを書く必要があります。今後、不具合が起きたときに、今回学んだことを活かしデバックしていきたいと思います。
では、また来週!(次回、第5週目)