文章目录

Ruby 面向对象:class 定义与方法调用

发布于 2026-04-03 20:34:20 · 浏览 2 次 · 评论 0 条

Ruby 面向对象:class 定义与方法调用


创建一个类,这是 Ruby 面向对象编程的起点。在 Ruby 中,使用 class 关键字定义类,类名必须以大写字母开头。

class Person
end

上面的代码定义了一个名为 Person 的空类。虽然它现在什么也不做,但已经是一个合法的类,可以用来创建对象。


给类添加实例变量和初始化方法。实例变量用于存储每个对象独有的数据,通常在 initialize 方法中设置。initialize 是 Ruby 的构造方法,当你用 new 创建对象时会自动调用。

class Person
  def initialize(name, age)
    @name = name
    @age = age
  end
end

这里 @name@age 是实例变量。它们的作用域属于单个对象,不同对象之间的实例变量互不影响。


创建对象并传入参数。使用类名后跟 .new 来实例化对象,并把需要的参数传递给 initialize 方法。

person1 = Person.new("Alice", 30)
person2 = Person.new("Bob", 25)

此时 person1person2 是两个独立的 Person 对象,各自拥有自己的 @name@age


定义实例方法来操作对象数据。实例方法可以读取或修改实例变量。在类内部用 def 定义方法。

class Person
  def initialize(name, age)
    @name = name
    @age = age
  end

  def introduce
    "Hi, I'm #{@name} and I'm #{@age} years old."
  end
end

现在你可以调用对象的 introduce 方法:

puts person1.introduce  # 输出: Hi, I'm Alice and I'm 30 years old.

注意:实例方法只能通过对象调用,不能直接通过类名调用。


暴露实例变量供外部读取。默认情况下,实例变量是私有的,外部无法直接访问。要让外部代码读取 @name,你需要定义一个“读取器”方法。

class Person
  def initialize(name, age)
    @name = name
    @age = age
  end

  def name
    @name
  end

  def introduce
    "Hi, I'm #{@name} and I'm #{@age} years old."
  end
end

现在可以获取名字:

puts person1.name  # 输出: Alice

Ruby 提供了快捷方式来生成这些读取器(或写入器)方法。


使用 attr_reader、attr_writer 或 attr_accessor 自动生成方法。这三个方法能省去手动编写 getter/setter 的麻烦。

  • attr_reader :name 自动生成 name 方法(只读)
  • attr_writer :name 自动生成 name= 方法(只写)
  • attr_accessor :name 同时生成 namename=(读写)

改写 Person 类:

class Person
  attr_accessor :name
  attr_reader :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def introduce
    "Hi, I'm #{@name} and I'm #{@age} years old."
  end
end

现在你可以读取和修改名字,但只能读取年龄:

person1.name = "Alicia"   # 修改名字
puts person1.name         # 输出: Alicia
puts person1.age          # 输出: 30
# person1.age = 31        # 报错!没有 age= 方法

定义类方法(而非实例方法)。类方法属于类本身,而不是某个对象。定义时在方法名前加 self.

class Person
  attr_accessor :name
  attr_reader :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def introduce
    "Hi, I'm #{@name} and I'm #{@age} years old."
  end

  def self.species
    "Homo sapiens"
  end
end

调用类方法时使用类名,而不是对象:

puts Person.species  # 输出: Homo sapiens

尝试用对象调用会失败:

# person1.species  # 报错!species 是类方法,不是实例方法

理解方法调用的查找顺序。当你调用一个方法时,Ruby 按以下顺序查找:

  1. 当前对象的类中是否有该实例方法?
  2. 如果没有,依次向上查找父类(直到 ObjectBasicObject
  3. 如果仍找不到,触发 method_missing(高级用法,此处不展开)

例如,所有对象都能调用 classobject_id 等方法,因为它们定义在 Object 类中。

puts person1.class      # 输出: Person
puts person1.object_id  # 输出一个数字(对象唯一标识)

调用带参数的方法。方法可以接收任意数量的参数,调用时按顺序传入。

class Person
  # ... 其他代码 ...

  def celebrate_birthday(years = 1)
    @age += years
    "Happy birthday! Now I'm #{@age}."
  end
end

调用这个方法:

puts person1.celebrate_birthday     # 默认加 1 岁
puts person1.celebrate_birthday(5)  # 加 5 岁

注意:years = 1 是默认参数,调用时不传则使用默认值。


链式调用多个方法。只要方法返回一个对象(几乎所有方法都返回对象),就可以连续调用。

# 假设我们添加一个 to_s 方法
class Person
  # ... 其他代码 ...

  def to_s
    "#{@name} (#{@age})"
  end
end

# 链式调用
result = Person.new("Charlie", 40).celebrate_birthday(2).to_s.upcase
puts result  # 输出: CHARLIE (42)

这里 celebrate_birthday 返回一个字符串(因为最后一行是字符串字面量),所以后续可以调用 upcase。但要注意返回值类型是否支持下一个方法。


避免常见错误

  1. 忘记 initialize 的拼写:不是 initconstructor,必须是 initialize
  2. 混淆类方法和实例方法def method 是实例方法,def self.method 是类方法。
  3. 试图直接访问实例变量:外部代码不能写 person1.@name,必须通过方法(如 person1.name)。
  4. 修改 attr_reader 字段attr_reader 只生成读取方法,没有 = 赋值方法。

完整示例:一个可运行的 Person 类

class Person
  attr_accessor :name
  attr_reader :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def introduce
    "Hi, I'm #{@name} and I'm #{@age} years old."
  end

  def celebrate_birthday(years = 1)
    @age += years
    "Happy birthday! Now I'm #{@age}."
  end

  def to_s
    "#{@name} (#{@age})"
  end

  def self.species
    "Homo sapiens"
  end
end

# 使用示例
alice = Person.new("Alice", 30)
puts alice.introduce
alice.name = "Alicia"
puts alice.celebrate_birthday(2)
puts Person.species

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文