問題
Rubyを勉強していると頻繁にエンカウントするこんなやつ。
attr_accessor :hoge attr_reader :hoge attr_writer :hoge
- メソッドがやっていることはなんとなくわかるが、いまいちしっくりこない
- なんだかモヤモヤする
という感情が湧いたので、言語化しておく。
結論
- attr_accessorは、インスタンス変数を参照したり、代入できるようにするメソッド
- attr_accessorは、attr_readerとattr_writerを組み合わせた書き方
attr_accessor
=attr_reader
+attr_writer
解説
attr_reader
attr_readerから見ていく。
attr_readerは、引数に定義した変数を読み取れるようにするメソッド。 これはコードを見たほうが理解が早い。
まず、attr_readerを使わない書き方から。
class Test def initialize(name) @name = name end def name @name end end test = Test.new("シュワちゃん") puts test.name
- initializeの引数にnameをとり、それをインスタンス変数の@nameに代入する
- nameメソッドを作り、@nameを参照できるようにしている
ターミナルで実行すると。
$ ruby test.rb シュワちゃん
となる。 attr_readerを使うと、次のように書ける。
class Test attr_reader :name def initialize(name) @name = name end # これはいらない # def name # @name # end end
attr_readerは、実際には以下のコードと同じことを表現している。
def name @name end
attr_writer
attr_writerは、引数に定義した変数に書き込みができるようになるメソッド。
attr_writerについても、まずはこれを使わずに書いてみる。
class Test attr_reader :name def initialize(name) @name = name end # 新しく追加 def name=(new_name) @name = new_name end end test = Test.new("シュワちゃん") puts test.name test.name = "シルベスター" puts test.name
新しく追加したのは以下の部分。
def name=(new_name) @name = new_name end
@nameに外部から新しい名前new_name
を代入できるようにしている。
よって、もともと「シュワちゃん」という文字列が代入されていた@nameに対し、シルベスターを入れてみる。
test.name = "シルベスター"
これをターミナルで実行すると。
$ ruby test.rb シュワちゃん シルベスター
インスタンス変数@nameの値が変更されている。
では、 attr_writerを使ってみよう。
class Test attr_reader :name attr_writer :name def initialize(name) @name = name end # 削除 # def name=(new_name) # @name = new_name # end end test = Test.new("シュワちゃん") puts test.name test.name = "シルベスター" puts test.name
attr_writer :name
を書くだけで、さきほどと同じような結果が得られる。
$ ruby test.rb シュワちゃん シルベスター
attr_accessor
そしてattr_accessorのお出番。
attr_readerとattr_writerはよく使われる。
「面倒だからattr_accessorにまとめようぜ?」と言って決めたかどうかはわからないが、attr_accessorを書くと参照と代入ができるようになる。
インスタンス変数 name に対する読み取りメソッドと書き込みメソッドの両方を定義します。 Module#attr_accessor (Ruby 2.7.0 リファレンスマニュアル)
class Test # 削除 # attr_reader :name # attr_writer :name # 追加 attr_accessor :name def initialize(name) @name = name end end test = Test.new("シュワちゃん") puts test.name test.name = "シルベスター" puts test.name
実行。
$ ruby test.rb シュワちゃん シルベスター
結果は変わらず。
最終的なコードはこちら。
class Test attr_accessor :name def initialize(name) @name = name end end
短くなった。
これでようやくモヤモヤが解けたかな。