Rubyのattr_accessor
と@インスタンス変数
について調べたのでまとめました。
外部からのインスタンス変数へのアクセス
class Foo
attr_accessor :bar
end
foo = Foo.new
foo.bar = 'instance!!!'
foo.bar # => "instance!!!"
foo.bar = 'instance!!!'
は一見、変数へ代入しているように見えますが、実態はattr_accessor
が作成した以下のようなFoo#bar=
メソッドを呼び出しています。
def bar=(val)
@bar = val
end
従ってfoo.bar = 'instance!!!'
の右辺はメソッドの引数です。また、Rubyにはsyntax sugarが用意されており、foo.bar=
と書かなくてもfoo.bar =
のように代入しているみたいに書けるのです。
参照についても同じくfoo.bar
は、@bar
を返すbar
という以下のようなメソッドを呼び出しています。
def bar
@bar
end
インスタンスメソッドからのアクセス
class Foo
attr_accessor :bar
def method_baz
p "#{@bar} from method_baz"
end
# attr_accessor :bar が定義されていなければ、barメソッドを呼び出せすNameErrorとなる
def method_qux
p "#{bar} from method_qux"
end
end
foo = Foo.new
foo.bar = 'instance!!!'
foo.method_baz # => "instance!!! from method_baz"
foo.method_qux # => "instance!!! from method_qux"
method_qux
では@
を付けなくてもインスタンス変数を参照しています。
これも上記と同じくattr_accessor
が作成した@bar
を返すbar
というメソッドを呼び出しているからです。
従ってアクセサが定義されていなければ、method_qux
はエラーになります。
インスタンスメソッドからのアクセス 2
class Foo
attr_accessor :bar
def method_quux
p bar
bar = 'blue!!!'
p bar
p @bar
p bar()
end
end
foo = Foo.new
foo.bar = 'red!!!'
foo.method_quux # => "red!!!"
# => "blue!!!"
# => "red!!!"
# => "red!!!"
method_quux
では1回目のp bar
と2回目のp bar
で出力される値が異なります。
これは1回目のp bar
ではattr_accessor
が作成している@bar
を返すbar
というメソッドを呼び出しているのに対して、2回目のp bar
では直前に定義された同名のローカル変数を参照しているためです。
この場合、インスタンス変数を参照したい時は素直に@bar
とするかbar()
と括弧を付けて明示的にメソッド呼び出しにする必要があります。
参考
以下の記事が参考になりました。
http://qiita.com/mogulla3/items/cd4d6e188c34c6819709