🍣

Ruby初心者向け:@nameとself.nameの違いを徹底解説

に公開

Ruby初心者向け:@nameとself.nameの違いを徹底解説

はじめに

Rubyを学び始めたとき、こんなコードを書いたことはありませんか?

class User
  def initialize(name)
    @name = name
  end
  
  def name
    @name
  end
  
  def set_name(new_name)
    @name = new_name
  end
  
  def greet
    puts "こんにちは、#{@name}です"
  end
end

でも先輩エンジニアから「attr_accessorselfを使った方がいいよ」と言われて、こんな風に書き直すように言われた経験はありませんか?

class User
  attr_accessor :name
  
  def initialize(name)
    self.name = name
  end
  
  def greet
    puts "こんにちは、#{self.name}です"
  end
end

@nameの方が分かりやすくない?」と思うかもしれませんが、実はself.nameを使うことには重要な理由があります。

attr_accessorとは?

まずattr_accessorについて理解しましょう。

# この1行は...
attr_accessor :name

# 実際にはこの2つのメソッドを自動生成している
def name
  @name
end

def name=(value)
  @name = value
end

つまり、attr_accessor :nameと書くだけで:

  • ゲッターメソッドname):値を取得する
  • セッターメソッドname=):値を設定する

この2つが自動的に作られるのです。

セッターメソッドの特殊な書き方

Rubyではname=というメソッドを特別扱いします:

# この2つは全く同じ意味
user.name = "田中"
user.name=("田中")  # 実際はこれが呼ばれている

つまり=を使った代入のような書き方でも、実際にはメソッド呼び出しなのです。

self.nameがセッターを呼ぶ仕組み

def initialize(name)
  self.name = name  # これがどう動くか?
end

実行の流れ:

  1. self.name = "yamada"と書く
  2. Rubyが「name=メソッドはあるかな?」と探す
  3. attr_accessorで作られたname=メソッドを発見
  4. name=("yamada")が実行される

実際に確認してみましょう:

class User
  def initialize(name)
    puts "initializeが呼ばれました: #{name}"
    self.name = name
    puts "initializeが終わりました"
  end

  def name=(new_name)
    puts "name=メソッドが呼ばれました: #{new_name}"
    @name = new_name
    puts "name=メソッドが終わりました"
  end
end

user = User.new("yamada")

出力:

initializeが呼ばれました: yamada
name=メソッドが呼ばれました: yamada
name=メソッドが終わりました
initializeが終わりました

なぜself.nameを使うべきなのか?

1. 将来の変更に強い

例えば、「名前は必ず大文字で始まるようにしたい」という要求が来たとします。

@nameを直接使った場合:

class User
  def initialize(name)
    @name = name.capitalize  # ここを修正
  end

  def set_name(new_name)
    @name = new_name.capitalize  # ここも修正
  end
  
  def some_method
    @name = "yamada"  # あ!大文字化を忘れた!
  end

  def greet
    puts "こんにちは、#{@name}です"  # → "yamadaです"(小文字のまま)
  end
end

self.nameを使った場合:

class User
  attr_accessor :name

  def initialize(name)
    self.name = name  # セッターを使用
  end

  def name=(new_name)
    @name = new_name.capitalize  # ここだけ修正すればOK
  end
  
  def some_method
    self.name = "yamada"  # セッターを通るので自動的に大文字化
  end

  def greet
    puts "こんにちは、#{self.name}です"  # → "Yamadaです"(正しく大文字化)
  end
end

2. 一貫性のあるインターフェース

# クラス外部での使い方
user.name = "田中"  # セッター経由
puts user.name     # ゲッター経由

# クラス内部でも同じインターフェースを使う
self.name = new_value  # セッター経由
puts self.name         # ゲッター経由

3. デバッグが楽

class User
  attr_accessor :name
  
  def name=(value)
    puts "nameが変更されました: #{value}"  # デバッグ用
    @name = value
  end
end

実践例で比較してみよう

❌ 推奨されない書き方

class User
  def initialize(name, email)
    @name = name
    @email = email&.downcase  # emailだけ小文字化
  end
  
  def name
    @name
  end
  
  def email
    @email
  end
  
  def set_name(new_name)
    @name = new_name  # 他の場所では大文字化の処理がない
  end
  
  def set_email(new_email)
    @email = new_email&.downcase
  end
end

✅ 推奨される書き方

class User
  attr_accessor :name, :email
  
  def initialize(name, email)
    self.name = name
    self.email = email
  end
  
  def name=(new_name)
    @name = new_name&.strip&.capitalize
  end
  
  def email=(new_email)
    @name = new_email&.strip&.downcase
  end
end

まとめ

  • @nameを直接使う → バラバラに管理、ミスしやすい
  • self.nameを使う → 1箇所で管理、ミスしにくい

最初は@nameの方が直感的に感じるかもしれませんが、self.nameを使うことで:

  1. 保守しやすいコードになる
  2. 一貫性のあるインターフェースを提供できる
  3. 将来の変更に対応しやすくなる

慣れてしまえば、「メソッド経由でアクセスする」という一貫したルールの方が分かりやすくなります。

ぜひ今日からattr_accessorselfを使ったコードを書いてみてください!

参考リンク

Discussion