0Pricing
Ruby Academy · 课时

prepend 与方法解析

祖先链

prepend 与方法解析 是 CoddyKit 上的免费 Ruby Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Ruby Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Ruby Academy 课程共包含 4 节课。

祖先链

调用方法时,Ruby 会搜索一个称为祖先链的列表。第一个匹配的定义会生效。理解这条链,有助于说明混入模块与继承如何相互作用。

class Animal; end
class Dog < Animal; end
p Dog.ancestors

方法查找顺序

Ruby 会先在对象的类中查找,然后查找该类包含的模块,再查找其父类,并沿着这条链继续向上,直到找到该方法。

module M
  def hello; "from module"; end
end
class C
  include M
  def hello; "from class"; end
end
puts C.new.hello

include 位于类的下方

被 include 的模块会位于链中类的正下方。类自身的方法优先于模块中的方法。

module M; end
class C
  include M
end
p C.ancestors  # [C, M, Object, ...]

认识前置插入

prepend 会将模块插入链中类的上方。这样,模块中的方法会在类自身的方法之前被找到,即优先执行。

module M
  def hello; "from module"; end
end
class C
  prepend M
  def hello; "from class"; end
end
puts C.new.hello

prepend 在链中的位置

检查祖先列表,查看 prepend 如何将模块放在类之前。

module M; end
class C
  prepend M
end
p C.ancestors  # [M, C, Object, ...]

从前置模块调用上级方法

由于前置模块会先运行,因此它可以通过调用 super 来到达原始方法,从而包装类的方法。这非常适合为行为添加装饰。

module Logged
  def save
    puts "before save"
    result = super
    puts "after save"
    result
  end
end
class Record
  prepend Logged
  def save
    puts "saving record"
    :ok
  end
end
p Record.new.save

混入模块中的 super

super 会沿着祖先链继续查找。在被包含的模块中,super 会到达父类;在前置模块中,它会到达类本身。

module Polite
  def greet; "Hi! " + super; end
end
class Person
  prepend Polite
  def greet; "I am here."; end
end
puts Person.new.greet

无需修改即可包装

prepend 让您可以围绕现有方法添加行为,而无需修改原始类代码,是猴子补丁的一种简洁替代方案。

module Timing
  def compute(n)
    puts "start"
    super
  end
end
class Calc
  prepend Timing
  def compute(n); n * n; end
end
puts Calc.new.compute(5)

多个模块的顺序

包含多个模块时,最后包含的模块最靠近类,因此会最先被查找。

module A; def who; "A"; end; end
module B; def who; "B"; end; end
class C
  include A
  include B
end
puts C.new.who  # B wins (included last)
p C.ancestors

include 与 prepend 总结

并列比较:

  • include M:链为 [Class, M, ...] —— 类的方法优先。
  • prepend M:链为 [M, Class, ...] —— 模块的方法优先,并且可以通过 super 进入类。
module M; end
class Inc; include M; end
class Pre; prepend M; end
p Inc.ancestors
p Pre.ancestors

整合运用

方法解析遵循祖先链:

  • 类的方法优先于被包含的模块。
  • 前置模块优先于类。
  • super 会沿链向上移动一步。
module Cap
  def name; super.capitalize; end
end
class User
  prepend Cap
  def name; "ada"; end
end
puts User.new.name

快速检查

测试您对方法解析的理解。

回顾

您学习了方法解析:

  • Ruby 会从上到下搜索祖先链。
  • include 位于类的下方;prepend 位于类的上方。
  • super 会到达链上方的下一个定义。
  • prepend 可以简洁地包装方法。
module Loud
  def speak; super.upcase; end
end
class Bot
  prepend Loud
  def speak; "beep"; end
end
puts Bot.new.speak

常见问题解答

「prepend 与方法解析」课时是免费的吗?

是的 — 「prepend 与方法解析」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Ruby Academy 课程的其余内容,请升级到 CoddyKit PRO。 Ruby Academy 课程共包含 4 节课。

「prepend 与方法解析」这节课中我会学到什么?

祖先链 你通过在浏览器中直接运行的动手代码来练习 Ruby Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Ruby Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Ruby Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「prepend 与方法解析」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Ruby Academy 课中编写并运行代码吗?

能。每节 Ruby Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 定义模块
  2. include 与 extend
  3. Comparable 与 Enumerable
  4. prepend 与方法解析
← 返回 Ruby Academy