#Rubyのクラスが分からない
チェリー本を読んでいざアウトプットしていこうと思ったものの、自分でプログラムを作るとなると中々解けずに難しい。。。
そんな僕と同じ悩みを抱えている方のために基礎問題を集めてみました。
基礎問題と言えど正直、曖昧な知識のままこの問題を解いていくと分からないことがあります。
出来れば答えを見ずに進めていくのが良いと思いますが、考えてもどうしても分からない場合は記事の下の方に回答を書いておきますので参考にして下さい。
そして、回答を読んでも分からないと言うことが僕自身ありましたので、分からなかった点まで記載していきます。
#問題(3問)
##①クラス変数とクラスメソッドについて
class Car
def self.run
@@count += 1
end
def count
@@count
end
end
car1 = Car.new
car1.run
car2 = Car.new
car2.run
car1.run
puts Car.count
こちらの記事の問題を参照しました。
●<問題>
上のプログラムは実行するとエラーが出ます。
ある箇所を修正して期待通りの出力ができる様にソースを変更してください。
(期待出力)
・インスタンスメソッドrun
を呼ぶとクラスの共有カウンタが1ずつ増加する。
・クラスメソッドcount
を呼ぶと現在のカウンタの値が返される。
3と表示されればオッケーです。
●<ヒント>
以下の記事が、この問題を解く上で非常に参考になりました。
https://qiita.com/mogulla3/items/cd4d6e188c34c6819709
##②特異メソッド
この記事を引用させていただきました。
class Food
def eat
puts "I like."
end
end
natto = Food.new()
wasabi = Food.new()
karaage = Food.new()
natto.eat #=>I like.
wasabi.eat #=>I don't like.
karaage.eat #=>I love.
●<問題>
コメントアウト通りの出力になる様にコードを変えてください。
##③Musicクラスを継承したRapクラスを定義する
こちらの記事を参照しました。
●<問題>
Rapクラスへ記述するコードを下記の出力結果から予測してください。
class Music
def mc
puts "This is #{@genre} of #{self.class.to_s}"
end
def initialize(genre)
@genre = genre
end
end
Rap.new("mc-battle").mc
(出力例)
This is mc-battle of Rap
Yo, mic check 1, 2.
#ー※※※※※※※※※※※解答※※※※※※※※※※※ー
##①クラス変数とクラスメソッドについて
クラス変数とクラスメソッドの使い方を理解していないと解けないですね。
●<クラス変数>
- クラスとそのインスタンスがスコープになる
- 定数と似ているがクラス変数は何度でも値を変更できる点で異なる
- クラスメソッド、インスタンスメソッド、クラス定義式内でアクセス可能
以下の記事が参考で、この問題を解く上で非常に参考になりました。
https://qiita.com/mogulla3/items/cd4d6e188c34c6819709
まず、見るべき点は2、6行目です。
class Car
def self.run #2行目
@@count += 1
end
def count #6行目
@@count
end
end
car1 = Car.new
car1.run
car2 = Car.new
car2.run
car1.run
puts Car.count
気づくことはなかったでしょうか?
最後の行を見てください。
puts Car.count
これは、Carクラスcountメソッドをそび出しているみたいですが、おかしくありませんか?
クラスをそのまま呼び出す際は、クラスメソッド出なければいけません。
修正すると、
class Car
def self.run #2行目
@@count += 1
end
def self.count #6行目
@@count
end
end
#-中略-
puts Car.count #最後の行
そして、2行目もおかしいですね。
こちらはインスタンスメソッドにしなければいけません。
class Car
def run #2行目/def self.runから変更
@@count += 1
end
end
car1 = Car.new
car1.run
なぜなら、classのそとではcar1
とインスタンスを作成しているからそのインスタンスを呼び出すためのメソッドとして、インスタンスメソッドにしなければいけません。
しかしこれで終わりではありません。
クラス変数 @@count
が定義されていません。
class Car
@@count = 0 #クラス変数の定義
def run #クラスメソッド
@@count += 1 #@@countはクラス変数
end
def self.count #インスタンスメソッド
@@count
end
end
car1 = Car.new
car1.run
car2 = Car.new
car2.run
car1.run
puts Car.count
# => $ ruby sample.rb
# => 3
これでオッケーです。
##②特異メソッド
そもそも、特異メソッドとは?
1つのインスタンス固有のメソッドのことを指します。
特異メソッドは、def オブジェクト名.メソッド名
で定義できます。
https://qiita.com/k-penguin-sato/items/d637dced7af32e4ec7c0
よって、
class Food
def eat
puts "I like."
end
end
natto = Food.new()
wasabi = Food.new()
karaage = Food.new()
#--追加--↓
def wasabi.eat
puts "I don't like."
end
def karaage.eat
puts "I love."
end
#--追加--↑
natto.eat
wasabi.eat
karaage.eat
同じクラスのインスタンスであるオブジェクトに、同じ名前の動作が異なるメソッドを定義します。
これが特異メソッドで、これはクラスに対してではなくクラスからできたインスタンスに対してのメソッドになります。
よってそれぞれのメソッドからの出力ができます。
(結果)
I like.
I don't like.
I love.
##③Musicクラスを継承したRapクラスを定義する
class Music
def mc
puts "This is #{@genre} of #{self.class.to_s}"
end
def initialize(genre)
@genre = genre
end
end
Rap.new("mc-battle").mc
・self.class.to_s
:Rap.new
の様に作られたインスタンス自体のクラス名を文字列に変換する。
では、Rapクラス
と、を作っていきます。
#--中略--
class Rap < Music
end
出力文字を見てください。
Yo, mic check 1, 2.
Musicクラスでは定義されていない出力ですので、Rapクラスで出力していきます。
最後の行のRap.new("mc-battle").mc
を見てみると、メソッドはmc
が使われていますので、記載していきます。
#--中略--
class Rap < Music
def mc
end
end
Musicクラス
を継承しているので必要な部分を記載すると
#--中略--
class Rap < Music
def mc
puts "Yo, mic check 1, 2."
end
end
しかしこれで終わりではないです。
まだ、現時点ではMusicクラスの呼び出しができていません。
どうすればいいでしょうか?
「super」メソッドを実行します。
superメソッドは、スーパークラスの中でその呼び出されたメソッドと同じメソッド名を持つメソッドを探して実行します。
それでは、書き換えると
class Music
def mc
puts "This is #{@genre} of #{self.class.to_s}"
end
def initialize(genre)
@genre = genre
end
end
class Rap < Music
def mc
super #追加コード
puts "Yo, mic check 1, 2."
end
end
Rap.new("mc-battle").mc
完成です。