1. 什么是模块?

模块(module)是一组方法和常量的集合,类似于类,但有以下区别:

  • 不能实例化:模块无法用 new 创建对象。
  • 用途
  • 命名空间:避免命名冲突。
  • Mixin:将方法混入类中,实现代码复用。

2. 定义模块

基本语法

module 模块名
  # 方法、常量等
end

示例

module Greeting
  def say_hello
    "你好,世界!"
  end
end
  • 模块名以大写字母开头(驼峰命名)。
  • 定义的方法默认是实例方法。

3. 模块作为命名空间

作用

将相关常量和方法分组,避免命名冲突。

示例

module MathTools
  PI = 3.14159

  def self.square(n)
    n * n
  end
end

puts MathTools::PI         # 3.14159
puts MathTools.square(5)   # 25

注意

  • :: 访问模块中的常量或模块方法。
  • self. 定义模块方法(类似类方法)。

4. 模块作为 Mixin

作用

通过 includeextend 将模块的方法混入类中。

include

将模块方法作为实例方法混入。

module Greetable
  def greet
    "你好,我是 #{@name}"
  end
end

class Person
  include Greetable  # 混入模块

  def initialize(name)
    @name = name
  end
end

p = Person.new("张三")
puts p.greet  # 你好,我是 张三
extend

将模块方法作为类方法混入。

module Tools
  def info
    "这是一个工具模块"
  end
end

class Calculator
  extend Tools  # 混入模块作为类方法
end

puts Calculator.info  # 这是一个工具模块

组合使用

module Utils
  def util_method
    "实用方法"
  end
end

class Test
  include Utils  # 实例方法
  extend Utils   # 类方法
end

t = Test.new
puts t.util_method      # 实用方法
puts Test.util_method   # 实用方法

5. 模块中的常量

示例

module Config
  VERSION = "1.0.0"
  AUTHOR = "李四"
end

puts Config::VERSION  # 1.0.0
puts Config::AUTHOR   # 李四

注意

  • 常量可以用 :: 访问。
  • 常量可以被修改(会发出警告):
  Config::VERSION = "2.0.0"  # 警告,但有效

6. 嵌套模块

示例

module Outer
  module Inner
    def say
      "嵌套模块方法"
    end
  end
end

class Demo
  include Outer::Inner
end

d = Demo.new
puts d.say  # 嵌套模块方法

注意

  • :: 分隔嵌套层级。
  • 嵌套模块常用于组织复杂代码。

7. 中文支持示例

模块名和方法支持中文:

module 问候
  def 你好
    "你好,大家!"
  end
end

class 学生
  include 问候
end

s = 学生.new
puts s.你好  # 你好,大家!

8. 实践案例

案例 1:日志模块

module Logger
  def log(message)
    puts "[#{Time.now}] #{message}"
  end
end

class Task
  include Logger

  def do_work
    log("任务开始")
    # 工作逻辑
    log("任务完成")
  end
end

task = Task.new
task.do_work

输出(示例):

[2025-03-22 10:00:00 +0800] 任务开始
[2025-03-22 10:00:00 +0800] 任务完成

案例 2:数学工具

module MathUtils
  PI = 3.14159

  def self.circle_area(radius)
    PI * radius ** 2
  end

  def square(n)
    n * n
  end
end

class Shape
  include MathUtils
end

puts MathUtils.circle_area(5)  # 78.53975
s = Shape.new
puts s.square(4)              # 16

案例 3:权限控制

module Permissions
  def can_edit?
    @role == "admin"
  end
end

class User
  include Permissions

  def initialize(role)
    @role = role
  end
end

admin = User.new("admin")
guest = User.new("guest")
puts admin.can_edit?  # true
puts guest.can_edit?  # false

9. include vs extend vs prepend

include

  • 方法作为实例方法。
  • 查找顺序:类方法 > 模块方法。

extend

  • 方法作为类方法。

prepend

  • 将模块方法插入类的继承链顶部,优先级高于类方法。
module Pre
  def say
    "来自 Prepend"
  end
end

class Example
  prepend Pre

  def say
    "来自类"
  end
end

e = Example.new
puts e.say  # 来自 Prepend

10. 注意事项

  • 不能实例化:模块无法用 new 创建对象。
  • 方法冲突:多个模块混入时,后混入的优先级更高(除非用 prepend)。
  • 作用域:模块方法需通过类或 :: 调用。

下一步

  • 练习:告诉我你想用模块做什么(命名空间、Mixin 等),我可以设计一个例子。
  • 问题解答:对模块用法有疑问吗?直接问我!
  • 深入学习:想了解模块在 Ruby 标准库或 Rails 中的应用吗?我可以继续讲解。

你现在想做什么?写代码、问问题,还是其他?