LoginSignup
0
0

More than 1 year has passed since last update.

紛らわしいRubyの@とselfについて

Posted at

Rubyのクラスについて紛らわしい@とselfの違いを自分の備忘録としてまとめます。

クラスの基本内容については先日まとめた記事をご確認ください。

紛らわしい@とself

クラス内でインスタンス変数を参照するのに、例えば@nameself.nameのように、@が使われる場合とselfが使われていることがあります。この違いは何なんでしょうか?

前提知識

インスタンス変数

@nameのように最初に@が付いたものはインスタンス変数そのものを表しています。つまり、データの入れ物それ自体を表しています。

インスタンスメソッド

一方、self.name()のように最初にselfが付いたものはインスタンスメソッドの呼び出しを表しています。下に例を示します。

class S
  def calc
    return 1+1
  end

  def call_calc
    # クラス内でインスタンスメソッドを呼び出すには`self.`をつけて呼び出す
    return self.calc() 
  end
end

s=S.new()
# インスタンスからインスタンスメソッドを呼び出すには`インスタンス名.`をつけて呼び出す
puts s.calc()  #=>2
puts s.call_calc()  #=>2

上のようにインスタンスメソッドは次のように実行できます。

  • クラス内でインスタンスメソッドを呼び出すにはself.メソッド名()をつけて呼び出す
  • コンストラクトしてから、インスタンスからインスタンスメソッドを呼び出すにはインスタンス名.メソッド名()をつけて呼び出す

インスタンス変数とインスタンスメソッドについてはRubyのクラスについてや「Rubyのメソッドについて(作成中)」でもまとめています。

@とselfが紛らわしい原因

上の内容だけであれば、@がついていたらインスタンス変数、selfと()がついていたらメソッドと話は単純なのですが、Rubyの様々な仕様によりこの違いが一見分かりづらくなっています。

()とselfの省略

Rubyでは関数やメソッドを呼び出す際に後ろの()を省略できます。さらに、クラス内でインスタンスメソッドを呼び出す際、self.メソッド名self.部分も省略することができます。このためインスタンスメソッドがあたかも変数のように見える場合があります。

クラスSに用意したインスタンス変数@nameを3通りの方法で取り出してみます。

class S
  def initialize(name="name")
    @name = name
  end

  # インスタンス変数と同名のインスタンスメソッドを用意する
  def name
    return @name
  end

  # 1. インスタンス変数(@)そのものを返す。
  def call_name_with_instance_variable
    return @name
  end

  # 2. self.インスタンスメソッドを呼び出し、その返り値を返す。
  def call_name_with_self
    return self.name()
  end

  # 3. インスタンスメソッドをselfと()の省略で呼び出し、その返り値を返す。
  def call_name_without_self
    return name
  end
end

s=S.new("太郎")
puts s.call_name_with_instance_variable()  #=>"太郎"
puts s.call_name_with_self()  #=>"太郎"
puts s.call_name_without_self()  #=>"太郎"

上のように、インスタンス変数を用意し、さらに、インスタンス変数と同名のインスタンスメソッドを用意した場合、

  • 1つ目のcall_name_with_instance_variableではインスタンス変数(=@name)が返されます。
  • 2つ目のcall_name_with_selfでは、nameメソッドの返り値(=@name)が返されます。
  • 3つ目のcall_name_without_selfでは、nameという変数のように見えますが、2つ目のself.name()からselfと()を省略したものです。2つ目と同様にnameメソッドの返り値(=@name)が返されます。

なお、3つ目のcall_name_without_selfを以下のように変形した場合を見てみます。

class S
~~~
  def call_name_without_self
    age=10
    return "私は#{name}で、#{age}才です"
  end
end

s=S.new("太郎")
puts s.call_name_without_self()  #=>"私は太郎で、10才です"

このとき、return文にある#{name}は先ほどの例と同様にメソッドの返り値を表します。一方で#{age}は直前に定義された変数を表します。どちらも同じように見えますが、メソッドと変数というように異なります。

まとめ

紛らわしい@とselfの違いを考えるために、インスタンス変数、インスタンスメソッド、selfと()の省略についてまとめました。

このようなRubyの仕様はインスタンスメソッドをあたかも変数のように扱えるという便利な面がある半面、間違いの原因となり得るので、普段から特に意識したいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0