目的
Rubyのattr_accessor、attr_reader、attr_writerについて、色々調べたり、手を動かしたりして、理解できたことをまとめておきます。
attr_accessor、attr_reader、attr_writer の定義
まずは、Rubyリファレンスで定義を見てみましょう。
attr_readerメソッドは、クラスやモジュールにインスタンス変数を読み出すためのアクセサメソッドを定義します。引数には、インスタンス変数名をシンボルか文字列で指定します(複数指定できます)。戻り値はnilです。
attr_writerメソッドは、クラスやモジュールにインスタンス変数を書き込むためのアクセサメソッドを定義します。引数には、インスタンス変数名をシンボルか文字列で指定します(複数指定できます)。戻り値はnilです。
attr_accessorメソッドは、クラスやモジュールにインスタンス変数を読み書きするためのアクセサメソッドを定義します。引数には、インスタンス変数名をシンボルか文字列で指定します(複数指定できます)。戻り値はnilです。
定義からは少し分かりづらいかもしれませんが、コードから理解してみましょう。
最初からまとめ
簡潔に言うと、
- attr_readerメソッドは、インスタンス変数を呼び出すメソッドを定義する。
- attr_writerメソッドは、インスタンス変数を書き込みメソッドを定義する。
- attr_accessorメソッドは、インスタンス変数を読み書きメソッドを定義する。
これを心に留めておいて、例を見てみましょう。
それぞれの意味
attr_readerメソッド
実は、attr_readerメソッドは以下のインスタンスメソッドと同じ意味です。
def name
@name
end
例:
class Member
def name
@name
end
end
member = Member.new
member.name = "Chimei" # => NoMethodError (undefined method 'name=')
member.name # => nil
attr_readerメソッドはクラスからインスタンス変数を読み出すしかできないので、
ここでmember.name = "Chimei"
、値を書き込みしようとするとNoMethodError (undefined method 'name=')
エラーが出てきます。
値が入ってないから、もちろんmember.name
はnilとなっています。
attr_writerメソッド
attr_writerメソッドは以下のインスタンスメソッドと同じ意味です。
def name=(name)
@name = name
end
例:
class Member
def name
@name
end
def name=(name)
@name = name
end
end
member = Member.new
member.name # => nil
member.name = "Chimei" # => "Chimei"
member.name # => "Chimei"
最初はmember.name
はnilですが、attr_readerメソッドはクラスにインスタンス変数を書き込みできるので、member.name = "Chimei"
で値を書き込んで、そしてmember.name
で値を確認してみると、確かに値が入っていましたね。
attr_accessorメソッド
attr_readerメソッドとattr_writerメソッドのフュージョンです。
つまり、クラスにインスタンス変数を読み出しだけではなく、書き込みもできる。
以下の二つ例が同じ意味です。
class Member
attr_reader :name
attr_writer :name
end
member = Member.new
member.name = "Chimei" # => "Chimei"
member.name # => "Chimei"
class Member
attr_accessor :name
end
member = Member.new
member.name = "Chimei"
member.name # => "Chimei"
三つ一緒に使ってみる
例1:
class Profile
attr_reader :name
attr_writer :job
attr_accessor :experience
end
profile = Profile.new
# 現在、値が何も入ってないから、値を書き込んでみよう
profile.name = "Shane" # => NoMethodError (undefined method `name=') 【書き込みできない】
profile.job = "teacher" # => "teacher"
profile.experience = 8 # => 8
# 値を確認
profile.name # => nil【書き込みできないから、値がnil】
profile.job # => NoMethodError (undefined method `job') 【読み出しできない】
profile.experience # => 8
例2:
class Profile
attr_reader :name
attr_writer :job
attr_accessor :experience
def initialize(name, job, experience)
@name = name
@job = job
@experience = experience
end
def intro
"Hi, I am #{@name}. I work as a #{@job} for #{@experience} years."
end
end
profile = Profile.new("Shane", "teacher", 8)
profile.intro # => "Hi, I am Shane. I work as a teacher for 8 years."
# 読み出す場合
profile.name # => "Shane"
profile.job # => NoMethodError (undefined method `age') 【読み出しできない(書き込むだけOK)】
profile.experience # => 8
# 値を変更しようとすると
profile.name = "Sid" # => NoMethodError (undefined method `name=') 【書き込みできない(読み出すだけOK)】
profile.job = "headhunter" # => "headhunter"
profile.experience = 3 # => 3
# 結果を確認
profile.intro # => "Hi, I am Shane. I work as a headhunter for 3 years."
initializeメソッドはインスタンスを初期化(ここでProfile.new
)時、自動で実行します。
そこで、三つの引数を値が入りました。 なので、1番目のprofile.intro
が特に問題ないです。
ですが、profile.name = "Sid"
で値を変更できないので、
2番目のprofile.intro
は nameの値は元々のShane
で出力してしまいました。
もう一度まとめ
attr_reader:インスタンス変数を呼び出すメソッドだけを定義したので、書き込みできない。
attr_writer:インスタンス変数を書き込みメソッドだけを定義したので、呼び出しできない。
attr_accessor:インスタンス変数を呼び出すと書き込むメソッドを定義しましたので、どちらでもできる。
######ここまでお読みいただきありがとうございました。多分文法上おかしいと思いますが、来日して2年目ですので日本語まだ勉強中です。文法ミスや誤字がありましたらあらかじめご了承ください。もちろん編集リクエストでご意見いただければと思います。
参考文献
https://www.rubyguides.com/2018/11/attr_accessor/
https://ref.xaio.jp/ruby/classes/module/attr_accessor
https://ref.xaio.jp/ruby/classes/module/attr_reader
https://ref.xaio.jp/ruby/classes/module/attr_writer