Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@baby-0105

Rubyの『クラス』関係の問題を集めてみて解いてみた。

Rubyのクラスが分からない

チェリー本を読んでいざアウトプットしていこうと思ったものの、自分でプログラムを作るとなると中々解けずに難しい。。。

そんな僕と同じ悩みを抱えている方のために基礎問題を集めてみました。

基礎問題と言えど正直、曖昧な知識のままこの問題を解いていくと分からないことがあります。

出来れば答えを見ずに進めていくのが良いと思いますが、考えてもどうしても分からない場合は記事の下の方に回答を書いておきますので参考にして下さい。

そして、回答を読んでも分からないと言うことが僕自身ありましたので、分からなかった点まで記載していきます。

問題(3問)

①クラス変数とクラスメソッドについて

sample.rb
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

②特異メソッド

この記事を引用させていただきました。

food.rb
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クラスへ記述するコードを下記の出力結果から予測してください。

sample.rb
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行目です。

sample.rb
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メソッドをそび出しているみたいですが、おかしくありませんか?

クラスをそのまま呼び出す際は、クラスメソッド出なければいけません。

修正すると、

sample.rb
class Car
  def self.run #2行目
    @@count += 1
  end

  def self.count #6行目
    @@count
  end
end

#-中略-

puts Car.count #最後の行

そして、2行目もおかしいですね。

こちらはインスタンスメソッドにしなければいけません。

sample.rb
class Car
  def run #2行目/def self.runから変更
    @@count += 1
  end
end

car1 = Car.new
car1.run

なぜなら、classのそとではcar1とインスタンスを作成しているからそのインスタンスを呼び出すためのメソッドとして、インスタンスメソッドにしなければいけません。

しかしこれで終わりではありません。

クラス変数 @@count が定義されていません。

sample.rb
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

よって、

food.rb
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クラスを定義する

sample.rb
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_sRap.newの様に作られたインスタンス自体のクラス名を文字列に変換する。

では、Rapクラスと、を作っていきます。

sample.rb
#--中略--
class Rap < Music
end

出力文字を見てください。
Yo, mic check 1, 2.

Musicクラスでは定義されていない出力ですので、Rapクラスで出力していきます。

最後の行のRap.new("mc-battle").mcを見てみると、メソッドはmcが使われていますので、記載していきます。

sample.rb
#--中略--
class Rap < Music
  def mc
  end
end

Musicクラスを継承しているので必要な部分を記載すると

sample.rb
#--中略--
class Rap < Music
  def mc
    puts "Yo, mic check 1, 2."
  end
end

しかしこれで終わりではないです。

まだ、現時点ではMusicクラスの呼び出しができていません。

どうすればいいでしょうか?

「super」メソッドを実行します。

superメソッドは、スーパークラスの中でその呼び出されたメソッドと同じメソッド名を持つメソッドを探して実行します。

それでは、書き換えると

sample.rb
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

完成です。

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
baby-0105
1997/01/05生まれ。Laravel / Vue

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?