🐡

Rubyのセッターの=っていらなくない??

2025/02/26に公開

セッターの=って必要?

class User
  def name=(name)
    @name = name
  end

  def name
    @name
  end
end

古典的なゲッターとセッターの書き方。
これはこう書くもの!とにかくそうなの!というノリで覚えていましたが
理解を深めるために色々試してみました。

私が読み返していた現場Railsの小さな注釈(P.17)には

Rubyでは末尾に=という記号がついたメソッド名を定義することで、属性をオブジェクトにセットするような形のメソッドを作ることができます。

とあります。

でもそもそも以下の形でもセットできるじゃん!=いらないじゃん!と思いました。

class User
  def name(name)
    @name = name
  end

  def name
    @name
  end
end

試しにローカルで"test.rb"を作って試してみたところ。。。

watabeyayoi@watabeyayoi test_app % rails c
Running via Spring preloader in process 14604
Loading development environment (Rails 6.0.3.4)
irb(main):001:0> require './test.rb'
=> true
irb(main):002:0> test = User.new
=> #<User:0x00007fa82d302a50>
irb(main):003:0> test.name("watabe")
Traceback (most recent call last):
        2: from (irb):3
        1: from test.rb:6:in `name'
ArgumentError (wrong number of arguments (given 1, expected 0))

あれっ!なんでだろう?と思ったけど答えは簡単でした。

すぐ後ろのゲッターと命名かぶってる!

class User
  def name(name) # nameメソッドでセッターを作っても...
    @name = name
  end

  def name # 同じ名前のため中身が上書きされる!
    @name
  end
end

つまり=をつけることによって、セットされた値を引っ張ってくる時に直感的に
test.name
とすることができる。

・・・でもこんな程度で諦めたくない!

えぇい、ゲッターの名前をかえてやる!

class User
  def name(name)
    @name = name
  end

  def name_getter
    @name
  end
end

情報をとってきたいときは後ろに"_getter"をつければよいのだ!
そうすればセッターで=を使わずに済む!(本末転倒)

実行したところ、目論見はうまくいったかのようにみえました

irb(main):002:0> require './test.rb'
=> true
irb(main):003:0> test = User.new
=> #<User:0x00007fa836856b10>
irb(main):004:0> test.name("watabe")
=> "watabe"
irb(main):005:0> test.name_getter
=> "watabe"

しかし・・・

irb(main):006:0> test.name = "yayoi"
Traceback (most recent call last):
        1: from (irb):6
NoMethodError (undefined method `name=' for #<User:0x00007fa836856b10 @name="watabe">)
Did you mean?  name

ア・・・!
値の再代入ができない!

いや、正確には
test.name("yayoi")
という方法でしか再代入ができなくなっている!

irb(main):006:0> test.name = "yayoi"
Traceback (most recent call last):
        1: from (irb):6
NoMethodError (undefined method `name=' for #<User:0x00007fa836856b10 @name="watabe">)
Did you mean?  name
irb(main):007:0> test.name("yayoi")
=> "yayoi" # やっぱりこれだとできる

そして気づきました。

あれっ・・・これらって同じじゃん・・・!

test.name="watabe"
test.name = "watabe"
test.name    =    "watabe"

空白がいくらあいていてもプログラミング上あんまり関係ないし
Rubyって()を省略することができるから・・・

test.name=("watabe")
 # ()を省略すると・・・
test.name= "watabe"

代入になってる!

実際はRubyでどう定義されているのか大元のコードとかみた方が良いのかもしれませんが、
なんとなくここまでで満足してしまいました。セッターの=は必要なんだなぁと実感が持てたので。

この先気になった方がいればぜひ調べてこの先のコメント頂けると🙏

Discussion