这些是 Ruby 方法,自动为 instance variables 生成 getter 和/或 setter 方法——消除样板代码。由于 instance variables (@name) 是私有的,不能从外部直接访问,你需要 accessor 方法来读写它们,而 attr_* 能简洁地生成这些方法。
它们解决的问题
()
= name
()
= value
class Person
attr_reader :name # generates a GETTER only (read-only): person.name
attr_writer :email # generates a SETTER only (write-only): person.email = ...
attr_accessor :age # generates BOTH getter and setter: person.age / person.age = ...
def initialize(name, age)
@name = name
@age = age
end
end
person = Person.new("Ann", 30)
person.name # "Ann" — reader
person.age = 31 # writer
person.age # 31 — reader
person.name = "X" # ❌ NoMethodError — name is read-only (attr_reader, no setter)
attr_reader → 仅 getter(只读访问)。attr_writer → 仅 setter(只写)。attr_accessor → getter 和 setter 都有(读写)。每个都接受命名 instance variables 的符号(symbols),并自动生成对应的方法——一行代码替代多个手写的方法定义。
class BankAccount
attr_reader :balance # ✅ balance is readable but NOT directly settable (protect it)
def initialize
@balance = 0
end
def deposit(amount) # changes go through a controlled method, not a raw setter
@balance += amount if amount > 0
end
end
选择 attr_reader(而非 attr_accessor)来定义不应该从外部随意修改的字段是良好的封装——只暴露你打算暴露的访问权限。
理解 attr_accessor/attr_reader/attr_writer 是 Ruby 的基础日常知识,因为它们出现在几乎每个 Ruby 类中。
它们存在的核心原因:instance variables (@name) 是私有的,不能从外部直接访问,所以你需要 accessor 方法来读或写它们——为每个属性手写那些 getter/setter 是乏味的样板代码。
这些方法自动生成 accessor(attr_reader 用于只读,attr_writer 用于只写,attr_accessor 用于读写),用单行简洁代码替代多个方法定义——这是 Ruby 优雅和简洁的标志。
理解每个方法生成什么,以及选择合适的方式也是良好封装的问题:对于不应该从外部随意修改的字段使用 attr_reader(只读),只在确实需要读写访问时使用 attr_accessor,这控制了对象状态的暴露方式(例如,使银行余额可读但只能通过受控方法修改)。
由于这些 accessor 在 Ruby 类(和 Rails 模型)中无处不在,了解它们如何工作、每个方法生成什么、以及如何选择以实现适当的封装,是编写和阅读 Ruby 类的必须知识——这是定义 Ruby 类时首先遇到的东西,反映了该语言对一个常见需求(对对象状态的受控访问)的简洁、富有表现力的态度。