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)
此时 person1 和 person2 是两个独立的 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同时生成name和name=(读写)
改写 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 按以下顺序查找:
- 当前对象的类中是否有该实例方法?
- 如果没有,依次向上查找父类(直到
Object和BasicObject) - 如果仍找不到,触发
method_missing(高级用法,此处不展开)
例如,所有对象都能调用 class、object_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。但要注意返回值类型是否支持下一个方法。
避免常见错误:
- 忘记
initialize的拼写:不是init或constructor,必须是initialize。 - 混淆类方法和实例方法:
def method是实例方法,def self.method是类方法。 - 试图直接访问实例变量:外部代码不能写
person1.@name,必须通过方法(如person1.name)。 - 修改
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
暂无评论,快来抢沙发吧!