こんにちは。
早く駆け出したい @iloveomelette です。
突然ですが、みなさんはあるメソッド内から別のメソッドを呼び出したい時のインスタンスメソッドとクラスメソッドの使い分けはできますでしょうか。
恥ずかしい話ではありますが、私はあやふやでよくNoMethodError
を出していました。
今回、勉強したことをここにアウトプットしていきますので、
私と同じく使い分けが曖昧な方はサラッとでも良いので、参考にしてくださると幸いです。
尚、ご指摘箇所がございましたら
ご教授いただけますと幸いです。
問題
いきなりですが、問題です。
以下のActress
クラスにあるyoshioka
メソッドはブロック内にあるarimura
メソッドを呼び出すことはできるでしょうか。
class Actress
def self.yoshioka
arimura
end
def arimura
puts 'Hello World!!'
end
end
Actress.yoshioka
正解は...
undefined local variable or method `arimura' for Actress:Class (NameError)
こうですね。エラーとなるのが正解です。
では、一見するとそのままいけそうなのに、このようにエラーが起きてしまうのでしょうか。
そもそもメソッドの呼び出し方って?
そもそもメソッドを呼び出すときに必要なものはなんでしょうか。
そうですね。「オブジェクト」です。
オブジェクト.メソッド(引数1..)
オブジェクトは「レシーバ」とも呼ばれます。
これが通常メソッドを呼び出すときの方法です。
インスタンスメソッドとクラスメソッド
今回登場してくるのが「インスタンスメソッド」と「クラスメソッド」です。
この両者の違いはなんでしょうか。
その名の通りなんですが、
- インスタンスメソッド:そのクラスのインスタンスに対して呼び出すことができるメソッド
- クラスメソッド:そのクラスに深く関係するもののインスタンスのデータ自体をどうこうするわけではない時に定義して呼び出すメソッド
# これはインスタンスメソッドの場合
class Anime
def takagi
puts 'Hello'
end
end
anime = Anime.new
anime.takagi
#=> Hello
# これはクラスメソッドの場合
class Anime
def self.kitagawa
puts 'Good night'
end
end
Anime.kitagawa
#=> Good night
クラスの中で、シンプルにメソッドを定義すると「インスタンスメソッド」となります。
「クラスメソッド」を定義したい場合、方法の一つとしてメソッドの前にself
をつけます。
メソッド内で他のメソッドを呼び出したい
クラスの外で呼び出す時はわかったけど、クラス内のメソッドの中で他のメソッドを使いたい時はどうすれば...?
ここが厄介なところで、self
は場所によって「インスタンス自身」にもなりうるし、「クラス自身」にもなりうる、ポケモンでいうところの「メタモン」みたいな子なんですね。
# これはインスタンスメソッドの場合
class Anime
def takagi
# ここの'self'は「インスタンス自身」
end
def self.kitagawa
# ここの'self'は「クラス自身」
end
end
ということは先ほどの問題を再度見てみると
class Actress
def self.yoshioka
arimura # この中は「クラス自身」、'arimura'は「インスタンス自身」
end
def arimura
puts 'Hello World!!'
end
end
Actress.yoshioka
こうですね。self
が表すオブジェクトの状態が異なっているのでNoMethodError
になってしまうんですね。
なので、yoshioka
メソッドの中でarimura
メソッドを呼び出すには以下のようにしないといけないですね。
class Actress
def self.yoshioka
arimura
end
def self.arimura
puts 'Hello World!!'
end
end
Actress.yoshioka
#=> Hello World!!
# または
class Actress
class << self
def yoshioka
arimura
end
def arimura
puts 'Hello World!!'
end
end
end
Actress.yoshioka
#=> Hello World!!
class << self ~ end
は複数のクラスメソッドを定義する際はメソッド前のself
を省略できるので便利ですね。
お疲れ様でした!
こうした少しの違いでエラーが起きてしまうので、しっかり概念を理解することが大切であると改めて感じました。
これからも精進していきます。
最後までお読みいただきありがとうございます。