20210404_アウトプット(Ruby)
今日やったこと
- ゼロからわかるRuby超入門の続き(7:メソッド〜8:クラスまで)8時間50分
1%の成長
- ようやくモヤモヤしていたRubyのクラスと向き合えた
新しく学んだこと
メソッド
putsがメソッド内にある時と外にある時の違い
- メソッド内にある時・・・表示させることもメソッドの仕事の一つとしている。
- メソッド外にある時・・・処理と表示は別にしており、表示結果を配列や変数にして別のところで使うこともできる。
💡 つまり、外に「表示させる」ことを持ってくると、利用範囲が広がる。
おさらい 戻り値と引数
- 戻り値とは? 呼び出し元へオブジェクトを返す
- 引数とは? メソッドへオブジェクトを渡す
- returnを使わない限り、最後の値が戻り値となる。
引数の便利な機能
キーワード引数
引数が2つ以上になったときは、キーワード引数を検討しよう!
- キーワード引数のメリットは、大きく2つある。
(1)引数の渡す順番が異なっていてもシンボルを手がかりに、きちんとオブジェクトが渡されること
(2)ラベルのようになるので可読性が上がること
def order(item:, size:) "#{item}を#{size}サイズでください" end puts order(item: "ポテト", size: "大盛り") #=> ポテトを大盛りサイズでください
デフォルト値の設定
- 通常はイコールで代入。
- シンボルの時だけ、キーと値のように書く。
- デフォルト値を設定すると、ラベルを探しに行くので、引数の順番がメソッドと呼び出し側で異なっていても適切に渡すことが出来るよ。
def order(item = "ハンバーガー") "#{item}をください" end puts order #=> ハンバーガーをください #💡引数を省略するとデフォルト値が適用
def order(item:, size: "普通") "#{item}を#{size}サイズでください" end puts order(item: "ポテト") #=> ポテトを普通サイズでください #💡:sizeを省略したところ、デフォルト値の「普通」が適用となり、引数エラーとならない。
スコープとは?(おさらい)
- 変数の見ることのできる範囲と、寿命のこと
- ローカル変数は、メソッド内でしか使うことが出来ない(外から呼び出したり、中のものを外で使えない)
クラスとは?(おさらい)
- クラスは工場。クラス自身が仕事をすることもあれば、そこから生まれたオブジェクトが仕事をすることもある
- 新しいクラスを作ることは、新しい特徴をもったキャラクター(プログラムの世界ではオブジェクト)を作ることができる。
- クラス名はキャメルケースにする。(=定数でもある)
- Methodsメソッドとは、そのオブジェクトで呼び出せるメソッドを一覧表示することが出来る。
レシーバ.methods
クラスを理解しよう!!!
🤔私:「超入門」からやり直したのもクラスに苦手意識があったからなんだ。どのオブジェクトもクラスに属していることはわかっているんだけど、オリジナルのクラスを組み立てるルールがいまいちわからないよ。
🥸先生:具体的に、どのようなルールが分からなかったの?
🤔私:attr_accessorを使ったり使わなかったり、引数渡したはずなのにエラーになってしまったり、いまいちふわっとした理解で書けないんだよね。
🥸先生:超入門本から基礎をしっかり理解しよう。
超入門本からこんなふうに理解した!
前提知識
- Rubyは全てがオブジェクトであり、何かしらのクラスに所属している。
クラス.new
で、クラスがインスタンスとして生成される。- レシーバとは、メソッドを使って呼び出されるオブジェクトの中身のこと。(例えば、
2.even?
では2の「整数オブジェクト」がレシーバであるし、["ポメ", "ペキニーズ"].size
では、["ポメ", "ペキニーズ"]
の「配列オブジェクト」がレシーバである)
今日理解したこと
クラスの中身を作るにあたって、目的が大きく4つあると理解。
目的 | 内容 | ポイント | コード例 |
---|---|---|---|
ただのローカル変数等を呼ぶため | そのままの文字列や渡された引数をシンプルに式展開する等 | 異なる動作は出来ない | ① |
インスタンス変数とするため | ゲッターやセッター(あるいはattr_accessor)を使い変数を取得・代入する | インスタンス毎に異なる動作が出来る/代入されて実行されることで初めてインスタンスとなる/複数のメソッドを跨いで使える | ② |
イニシャライズメソッドとするため | newメソッドでクラスを生成時に引数で渡すことによって、生成時に持っていて欲しいデータを設定する | 引数として届くことが他のメソッドと違う点 | ③ |
クラスメソッドとするため | クラス全体を呼び出される中身として表示する | クラスが実行するのでオブジェクトを作ることなく呼び出すことが出来る(全体の振る舞い) | ④ |
ただのローカル変数等を呼ぶため①
class Drink def order(name) puts "#{name}をください" end end drink = Drink.new drink.order("お茶") #=> お茶をください
インスタンス変数とするため②
class Drink def name=(text) #🌟インスタンス変数へ代入している(👈attr_writer :name) @name = text end def name #🌟インスタンス変数を外から取得出来るようにする(👈attr_reader :name) @name end end drink = Drink.new drink.name= "お茶" #💡代入している。「drink.name = "お茶"」でも可。 puts drink.name #=> お茶
- ゲッターとセッターは
attr_accessor :name
と一つにすることが出来る。
イニシャライズメソッドとするため③
class Drink def initialize(name) @name = name end def name @name end end drink = Drink.new("牛乳") puts drink.name #=> 牛乳
- newメソッドへ渡す値を帰ると、色々なDrinkオブジェクトを作れる。
- 外から呼び出すには、参照用のメソッドを上記のように定義するか、アクセサメソッドが必要である。(ようやく繋がった・・・)
クラスメソッドとするため④
class Cafe def self.welcome "いらっしゃいませ!" end end puts Cafe.welcome 🌟呼び出す際はクラス.メソッド名だけでOK #=> いらっしゃいませ!
あるいは
class Cafe class << self def welcome "いらっしゃいませ!" end end end puts Cafe.welcome #=> いらっしゃいませ!
- 下の段は、複数のクラスメソッドを書くときに便利(ネストが一つ深くなる)またちょっと先の話になるけれどクラスメソッドをprivateメソッドにしたいときは
class << self
の構文を使うよ。 - インスタンスメソッドからクラスメソッドを呼ぶことも出来る(
self.class.クラスメソッド
またはクラス.クラスメソッド
)逆に、クラスメソッドからインスタンスメソッドを呼び出すことは出来ないので注意。(どのインスタンスメソッドであってもクラスメソッドは共通なので呼び出せるが、インスタンスメソッドはレシーバがその都度異なるため) クラス.new
のnew
はクラスメソッドだよ!!!
そのほか便利なメソッド
メソッド | 読み方 | 内容 |
---|---|---|
instance_variablesメソッド | インスタンスバリアブル | インスタンス変数の変数名一覧を取得するメソッド |
ancestorsメソッド | アンセスター(祖先)メソッド | 継承関係上の祖先をたどることが出来るメソッド |
継承のルール
- 継承は
<
一つ!(つい、クラスメソッドの2つとごっちゃになる) - 継承の目的は、「似たメソッドを何度も書くの面倒」なので、それらを引き継ぎつつ、「一部変えたい」という時に使える。
- ”「子クラス」は「親クラス」の一種である”と声に出しても違和感がない時は適切な継承と言える。
- 親子のクラス🐓🐤で同名のメソッドがある時は、「最初に該当したメソッド🐤」を呼び出す
- もし「最初に該当したメソッド🐤」ではなく、親クラスの同名メソッドを呼び出したい時は「🐓super🐓」と書く。
- 同名の「子クラス」と「親クラス」のインスタンス変数や、privateメソッドは、継承がきっかけでオーバーライドを引き起こし、バグを起こす原因にもなりうるので注意。
制限のルール
🤔私:それぞれのメソッドのルールを上手く使えば外からも中からも呼び出せるようになったね!
🥸先生:あえて「レシーバを指定して呼び出すことができないインスタンスメソッド」としてprivate
メソッドがあるよ。
🤔私:出来ること減らしてしまうので、無意味では?どうしてプライベートにするの?
🥸先生:private
メソッドにする=外から呼び出さないようにすると明示することで「このクラスとオブジェクトではAメソッドではなくBメソッドを使ってくださいね」と設計上の意図を他のプログラマーに伝える大事な役割を担っているよ。