Rubyのクラスについて、インスタンス変数の参照・代入とそれを可能にするattr_accessorをまとめます。
クラスの基本内容については先日まとめた記事をご確認ください。
selfと@の違い、selfと()の省略についてはこちらの記事をご確認ください。
インスタンスメソッド、クラスメソッド、メソッドの呼び出し制限によるプライベートメソッドについてはこちらの記事をご確認ください。
インスタンス変数に対する読み取りと書き込み
インスタンス変数は直接参照・代入できない
インスタンス変数は、クラスの中では参照(値を取り出す)・代入が可能ですが、クラスの外からは直接参照・代入はできません。
例) インスタンス変数を直接参照・代入するとエラーになる
class S
def initialize(name="name")
@name = name
end
end
s=S.new("aaa")
puts s.@name #=>syntax error, unexpected tIVAR
puts s.@name="bbb" #=>syntax error, unexpected tIVAR
puts s.name #=>NoMethodError
puts s.name="bbb" #=>NoMethodError
そもそも上記のようなインスタンス名.メソッド名
で呼び出すためにはインスタンスメソッドを作成する必要があります。
インスタンス変数を参照・代入するメソッドを作る
インスタンス変数を参照・代入するメソッドは以下のように呼ばれます。
- ゲッタ:インスタンス変数の値を取り出すメソッド
- セッタ:オブジェクトのインスタンス変数に値を代入するためのメソッド
例2)インスタンス変数を参照・代入するインスタンスメソッドを作る
class S
def initialize(name="name")
@name = name
end
# ゲッタ
def name
@name
end
# セッタ
def name=(string)
@name = string
end
end
s=S.new("aaa")
puts s.name #=>aaa
puts s.name="bbb" #=>bbb
ゲッタとセッタを定義することでインスタンスメソッドの参照・代入が可能になりました。しかしインスタンス変数が多くなると、インスタンス変数ごとにゲッタとセッタを定義するのは煩雑になります。
そこで、attrで始まるメソッドを使用します。
attrで始まるメソッド4つ
- attr_reader
インスタンス変数の読み取りメソッド(ゲッタ)を定義するメソッドです。インスタンス変数の参照はできても代入はできません。
class S
attr_reader :name
def initialize(name="name")
@name = name
end
end
s=S.new("aaa")
puts s.name #=>aaa
puts s.name="bbb" #=>NoMethodError
詳しく言うと、attr_reader
は上のS
自体のインスタンスメソッドではなく、Module
というクラスのインスタンスメソッドらしいです。
参考:class Module (Ruby 3.1 リファレンスマニュアル)
- attr_writer
インスタンス変数の書き込みメソッド(セッタ)を定義するメソッドです。インスタンス変数の参照はできませんが、代入はできます。
class S
attr_writer :name
def initialize(name="name")
@name = name
end
end
s=S.new("aaa")
puts s.name #=>NoMethodError
puts s.name="bbb" #=>bbb
- attr
第1引数に指定したインスタンス変数の読み取りのためのインスタンスメソッド(ゲッタ)を定義するメソッドです。第2引数にtrueを指定した場合には書き込みメソッド(セッタ)も同時に定義します。
class S
attr :name, true
def initialize(name="name")
@name = name
end
end
s=S.new("aaa")
puts s.name #=>aaa
puts s.name="bbb" #=>bbb
class S
# 第一引数は複数指定できる。
attr :name, :email
def initialize(name="name", email="email")
@name = name
@email = email
end
end
s=S.new("aaa", "aaa@email.com")
puts s.name #=>aaa
puts s.email #=>aaa@email.com
しかし、このattrメソッドは、第一引数を複数指定することは可能ですが、第一引数を複数指定しかつ第二引数にtrueを指定することができません。
class S
# 第一引数を複数指定し、第二引数をtrueにしてセッタも定義するよう指定するが、エラーになる
attr :name, :email, true #=>TypeError
def initialize(name="name", email="email@email.com")
@name = name
@email = email
end
end
- attr_accessor
そこで、attr_accessorの出番です。
attr_accessorはインスタンス変数に対する読み取りと書き込みのメソッド(ゲッタとセッタ)の両方を定義するインスタンスメソッドです。
attr_accessorはattr_readerとattr_writerをあわせたようなもの、もしくはattrの第1引数が複数のときも第2引数にtrueを指定できるものです。
class S
attr_accessor :name, :email
def initialize(name="name", email="email")
@name = name
@email = email
end
end
s=S.new("aaa", "aaa@email.com")
puts s.name #=>aaa
puts s.name="bbb" #=>bbb
puts s.email #=>aaa@email.com
puts s.email="example@email.com" #=>example@email.com
まとめ
rubyでよく使われるattr_accessorについて説明するために、attr_reader、attre_writer、attrについても言及しながらまとめました。attrについては調べて初めて存在を知りました。また、attr_accessorは特に意識せず便利機能のように使っていましたが、その裏でゲッタとセッタのメソッドが自動で定義され、クラスの外からインスタンス変数の参照や代入ができるようになるということが分かりました。コードを書く際に、その仕組みが何なのかを理解してから使うことを普段から意識したいと感じました。