Rubyの「attr_accessor」ってなんぞや、という人へ

Rubyにattr_accessorってメソッドありますよね。こんなのです。

class Book
  attr_accessor :title, :price

  def initialize(title, price)
    @title = title; @price = price
  end
end

「getter」と「setter」を定義してくれるメソッドですが、Rubyからプログラミングを始める初心者殺しだと思ってます。

「getter」と「setter」が何者なのか理解しきれなかった当初は苦しみました。

特にsetterメソッド。

def hogehoge=(val)

ってなんぞや・・・

ということで今回は実際に自分が詰まった箇所「attr_accessor」の説明と

def title=(val)

end

という「setterメソッド」定義の最初の躓きポイントをプログラミング初心者に向けて分かりやすく書いていきます。

スポンサーリンク

def title=(val) ってなんだ

以下のコードにて、「Bookインスタンス」が「インスタンス変数title」を呼び出したり「インスタンス変数price」に値を代入したり出来ているのは「attr_accessor」のおかげです。

ここまでは初心者でも「そういうものなんだ」と理解出来ます。

class Book
  attr_accessor :title, :price

  def initialize(title, price)
    @title = title; @price = price
  end
end

book = Book.new("Programming Ruby", 1980)
puts book.title
book.price = 2000
puts book.price

では、「attr_accessorを使わない場合」の記述を見てみます。

class Book

  def initialize(title, price)
    @title = title; @price = price
  end

  def title
    @title
  end

  def title=(val)
    @title = val
  end

  def price
    @price
  end

  def price=(val)
    @price = val
  end
end

「attr_accessor」を記述しない代わりに、「4つ」インスタンスメソッドが増えました。

単に1つのインスタンス変数にアクセスする代わりに「読み込み用」と「書き込み用」のメソッドを用意しただけです。

初めの頃、ある一行にとても違和感を感じました。

def title=(val)

これです。

def title=(val) の正体

「メソッド定義ってこうやるんだよね?」

def title

「そうそう、def の後に打ち込んだ文字のメソッドが定義される」

じゃあこれは?

def title=(val)

「うわ、文字のあとに変な =(val) が付いている・・・」

これだけで大パニック。今までのメソッド定義の固定観念が覆される衝撃です。
しばらくこのコードの意味不明さには悩みました。

「titleだけのメソッドがあるからこっちが「setter」ってやつに違いないはず・・・」

「そもそもvalってなんだよ・・・」

正解

def title=(val) とは

book.title = "test"

と「title」への代入式を書いた時に呼び出されるメソッド。
決して「title=(val)」という命名のメソッドではない。

分からなかった理由

  1. 「メソッド名」と 「=」 と 「引数」がくっついてたから
  2.  valが何かの魔法のコトバだと思い込んでたから

代入と言ったら title = val のようなスペースを空けた形だけだと考えてました。
また、valも単なるvalueの略で「引数」を表していただけ。

strやらvalやら変数の略称ってたくさんあります。
ただ、プログラミング初心者にはそれが躓く原因となったりします。
省略した書き方を知らないと、意外な所で理解の妨げになる恐れがありそうです。

参考

アクセスメソッド / RubyLife

attr_accessor (Module) / Rubyリファレンス

Railsから入った人へ【attr_accessor】って? / Qiita(@Hassan)

Rubyのメソッド定義について def test = (val); end / teratail

コメント

  1. Tambourine より:

    決して「title=(val)」という命名のメソッドではない。

    誤解を招きそうな表現ですが、それは「title=」という命名のメソッドです。Rubyのメソッド名に記号が含まれることは、ちょいちょいあります。

    上のBookクラスのインスタンスbにたいして、「b.title=(“広辞苑”)」と書くのと「b.title = “広辞苑”」と書くのは全く同じです・・・というか、後者の書き方は前者を簡単に書くための記法に過ぎません。同様に、「b.title + “新明解”」は「b.title().+(“新明解”)」という意味になります。つまり、+も演算子ではなく、名前に記号を含んだ(というか記号1文字だけの)メソッドです。

    この様にRubyでは人間が書きやすいようにもの凄く頑張っているため、Rubyコードを解釈するプログラムは超複雑になって困っているらしいですが、「Rubyを作る人より使う人の方が多いのだから、作る人が苦労すべきだ」というのがRubyを作っている人達のポリシーなのです。

    • tomuziso より:

      コメントありがとうございます。

      誤解を招きそうな表現ですが、それは「title=」という命名のメソッドです。Rubyのメソッド名に記号が含まれることは、ちょいちょいあります。

      使う人が書きやすい「title = val」のみが代入形式だと考えていると、
      「title=(val)」の「=(val)」がメソッド呼び出しだと気付かず、普通のメソッド定義と勘違いしてしまうのでは、という意図で書いていました。

      代入と言って最初に思い浮かべるのは、

      「title = val」のような「=」の前後にスペースを含む書き方。

      しかし、Rubyではこちらがシンタックスシュガーであり、上記は「title=」というメソッドを呼び出しているだけ、ということですよね。
      http://i.loveruby.net/ja/rhg/book/spec.html