Ruby 中 load、require 和 require_relative 的详解
本文档整理了 load、require 和 require_relative 的作用、区别、应用场景、代码举例,以及 load 的参数。基于 Ruby 3.x 版本的标准行为,内容简洁实用。
1. 作用概述
- load: 加载并执行指定的 Ruby 文件。每次调用都会重新加载文件,即使文件已经被加载过。这意味着文件中的代码会多次执行。
- require: 加载并执行指定的 Ruby 文件,但只加载一次。如果文件已经被加载,后续调用会直接返回 true,而不重新执行。require 会搜索 Ruby 的加载路径
($LOAD_PATH 或 $:)。 - require_relative: 类似于 require,但路径是相对于当前文件的目录计算的。只加载一次,不搜索 $LOAD_PATH。
这些方法的主要目的是模块化代码:将代码拆分成多个文件,便于维护和复用。它们返回 true(如果加载成功)或 false(如果 require/require_relative 已加载过),load 总是返回 true。
2. 区别总结
用表格比较区别:
| 方面 | load | require | require_relative |
|---|---|---|---|
| 加载次数 | 每次调用都重新加载和执行 | 只加载一次(已加载则跳过) | 只加载一次(已加载则跳过) |
| 路径计算 | 绝对路径或相对当前工作目录 | 搜索 $LOAD_PATH(加载路径) | 相对当前文件的位置 |
| 文件后缀 | 可以省略 .rb,但不推荐 | 可以省略 .rb | 可以省略 .rb |
| 异常处理 | 文件不存在抛 LoadError | 文件不存在抛 LoadError | 文件不存在抛 LoadError |
| 性能影响 | 可能多次执行,适合动态变化 | 高效,一次加载 | 高效,一次加载,路径更可靠 |
| 常见用途 | 开发调试、配置文件 | 加载 gem 或标准库 | 项目内部文件依赖 |
| 安全性 | 易导致重复加载问题 | 内置重复加载检查 | 内置重复加载检查,路径更明确 |
- 关键不同点:load 不检查是否已加载,适合需要重新评估的文件;require 和 require_relative 有内置的 $LOADED_FEATURES 检查,避免重复;require_relative 解决了 require 的路径依赖问题。
3. 应用场景
-
load:
- 场景:开发环境中,需要反复修改并重新加载文件;或加载可能动态变化的配置文件。
- 为什么:总是重新执行,能捕捉变化。但生产环境中慎用,避免性能开销或副作用。
- 示例:IRB 或 Rails console 中测试代码;加载插件脚本。
-
require:
- 场景:加载第三方 gem、标准库或项目中的共享模块。一旦加载,全局可用。
- 为什么:标准实践,高效且安全。Ruby 的 gem 系统依赖它。
- 示例:require 'json';require 'active_record' 在 Rails 中。
-
require_relative:
- 场景:项目内部文件依赖,尤其是文件结构复杂或在不同目录运行时。
- 为什么:路径相对当前文件,避免硬编码绝对路径或修改 $LOAD_PATH。
- 示例:app/models/user.rb 中加载 app/helpers/user_helper.rb。
注意:在脚本顶部通常用 require/require_relative;在测试或动态环境中用 load。优先 require_relative > require > load。
4. 代码举例
假设项目结构:
my_project/
├── main.rb
├── lib/
│ └── utils.rb
└── config/
└── settings.rb
-
utils.rb:
module Utils def greet puts "Hello from Utils!" end end puts "Utils loaded at #{Time.now}" -
settings.rb:
SETTINGS = { env: 'development' } puts "Settings loaded at #{Time.now}"
示例1: load(重新加载)
load 'config/settings.rb' # 第一次
load 'config/settings.rb' # 第二次,重新执行
puts SETTINGS[:env]
输出:显示两次加载时间和 development。
示例2: require(只加载一次)
$LOAD_PATH << 'lib'
require 'utils' # 第一次
require 'utils' # 第二次,不执行
include Utils
greet
输出:只打印一次加载时间和 "Hello from Utils!"。
示例3: require_relative(相对路径)
require_relative 'lib/utils' # 第一次
require_relative 'lib/utils' # 第二次,不执行
include Utils
greet
输出:类似 require。
注意:文件不存在抛 LoadError;在模块化项目中注意副作用。
5. load 的参数
load 的签名:load(filename, wrap = false) → true
- filename (String, 必选):文件路径(绝对/相对)。不存在抛 LoadError。
- wrap (Boolean, 可选,默认 false):true 时,在匿名模块中执行,隔离命名空间;false 时,直接在当前作用域执行。
作用:filename 指定源;wrap 用于隔离(Ruby 1.9+)。load 总是重新加载,不搜索 $LOAD_PATH。
示例1: 默认 (wrap=false)
load 'plugin.rb' # 内容全局可见
示例2: wrap=true
load 'plugin.rb', true # 内容隔离,不可直接访问
注意:慎用重复加载;避免从用户输入加载文件。