Ruby 4.0.0 发布
由 naruse 发布于 2025 年 12 月 25 日
我们很高兴地宣布 Ruby 4.0.0 的发布。Ruby 4.0 引入了“Ruby Box”和“ZJIT”,并增加了许多改进。
Ruby Box
Ruby Box 是一项新的(实验性)功能,用于提供定义的分离。当指定环境变量 RUBY_BOX=1 时,Ruby Box 将被启用。类为 Ruby::Box。
加载到 box 中的定义与 box 是隔离的。Ruby Box 可以将 monkey patch、全局/类变量的更改、类/模块定义以及加载的原生/Ruby 库与其他 box 隔离/分开。
预期用例包括:
- 在 box 中运行测试用例,以保护其他测试,当测试用例使用 monkey patch 覆盖某些内容时。
- 并行运行 Web 应用 box,以便在 Ruby 进程中的应用服务器上执行蓝绿部署。
- 并行运行 Web 应用 box,通过使用 Ruby 代码检查响应差异,来评估特定时间段内的依赖项更新。
- 用作实现某种“包”(高级)API(尚未设计)的基础(低级)API。
有关“Ruby Box”的详细信息,请参阅 Ruby::Box。[Feature #21311] [Misc #21385]
ZJIT
ZJIT 是一个新的即时(JIT)编译器,它是 YJIT 的下一代产品。您需要 Rust 1.85.0 或更高版本才能构建支持 ZJIT 的 Ruby,并且在指定 --zjit 时启用 ZJIT。
我们正在为 Ruby 构建一个新的编译器,因为我们希望提高性能上限(更大的编译单元大小和 SSA IR),并通过成为更传统的的方法编译器来鼓励更多外部贡献。有关更多详细信息,请参阅 我们的博客文章。
ZJIT 比解释器快,但尚未达到 YJIT 的速度。我们鼓励您尝试 ZJIT,但现在可能要暂缓在生产环境中使用它。请继续关注 Ruby 4.1 ZJIT。
Ractor 改进
Ruby 的并行执行机制 Ractor 获得了一些改进。引入了一个新类 Ractor::Port 来解决消息发送和接收相关的问题(请参阅 我们的博客文章)。此外,Ractor.shareable_proc 使 Ractor 之间共享 Proc 对象更加容易。
在性能方面,许多内部数据结构得到了改进,以显著减少全局锁的争用,从而实现更好的并行性。Ractors 现在共享的内部数据也更少,从而在并行运行时减少 CPU 缓存争用。
Ractor 最初于 Ruby 3.0 作为一项实验性功能推出。我们的目标是在明年移除其“实验性”状态。
语言更改
-
*nil不再调用nil.to_a,这与**nil不调用nil.to_hash类似。[Feature #21047] -
行首的逻辑二进制运算符(
||、&&、and和or)会继续上一行,就像链式点操作符一样。以下代码示例是等效的:if condition1 && condition2 ... end以前
if condition1 && condition2 ... endif condition1 && condition2 ... end
核心类更新
注意:我们只列出突出的类更新。
-
Array
- 添加了
Array#rfind,作为array.reverse_each.find的更高效替代方案。[Feature #21678] - 添加了
Array#find,作为Enumerable#find的更高效覆盖。[Feature #21678]
- 添加了
-
Binding
-
Binding#local_variables不再包含数字参数。此外,Binding#local_variable_get、Binding#local_variable_set和Binding#local_variable_defined?拒绝处理数字参数。[Bug #21049] -
添加了
Binding#implicit_parameters、Binding#implicit_parameter_get和Binding#implicit_parameter_defined?来访问数字参数和“it”参数。[Bug #21049]
-
-
Enumerator
-
Enumerator.produce现在接受一个可选的size关键字参数来指定枚举器的长度。它可以是整数、Float::INFINITY、可调用对象(如 lambda)或nil来表示未知长度。如果不指定,长度默认为Float::INFINITY。# Infinite enumerator enum = Enumerator.produce(1, size: Float::INFINITY, &:succ) enum.size # => Float::INFINITY # Finite enumerator with known/computable size abs_dir = File.expand_path("./baz") # => "/foo/bar/baz" traverser = Enumerator.produce(abs_dir, size: -> { abs_dir.count("/") + 1 }) { raise StopIteration if it == "/" File.dirname(it) } traverser.size # => 4
-
-
ErrorHighlight
-
当抛出 ArgumentError 时,现在会显示方法调用(调用者)和方法定义(被调用者)的代码片段。[Feature #21543]
test.rb:1:in 'Object#add': wrong number of arguments (given 1, expected 2) (ArgumentError) caller: test.rb:3 | add(1) ^^^ callee: test.rb:1 | def add(x, y) = x + y ^^^ from test.rb:3:in '<main>'
-
-
Fiber
- 引入了对
Fiber#raise(cause:)参数的支持,类似于Kernel#raise。[Feature #21360]
- 引入了对
-
Fiber::Scheduler
-
引入
Fiber::Scheduler#fiber_interrupt以用指定的异常中断一个 fiber。初始用例是当中断一个正在等待阻塞 I/O 操作的 fiber 时,该 I/O 操作被关闭。[Feature #21166] -
引入
Fiber::Scheduler#yield以允许 fiber 调度器在禁用信号异常时继续处理。[Bug #21633] -
重新引入
Fiber::Scheduler#io_close钩子,用于异步IO#close。 -
在刷新 IO 写缓冲区时调用
Fiber::Scheduler#io_write。[Bug #21789]
-
-
File
- 在 Linux 上,当内核和文件系统支持 statx 系统调用时,
File::Stat#birthtime现在可用。[Feature #21205]
- 在 Linux 上,当内核和文件系统支持 statx 系统调用时,
-
IO
-
IO.select接受Float::INFINITY作为超时参数。[Feature #20610] -
已移除通过
IO类方法以|开头的进程创建的已弃用行为。[Feature #19630]
-
-
Kernel
-
Kernel#inspect现在检查#instance_variables_to_inspect方法是否存在,允许控制在#inspect字符串中显示哪些实例变量。class DatabaseConfig def initialize(host, user, password) @host = host @user = user @password = password end private def instance_variables_to_inspect = [:@host, :@user] end conf = DatabaseConfig.new("localhost", "root", "hunter2") conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root"> -
已移除通过
Kernel#open以|开头的进程创建的已弃用行为。[Feature #19630]
-
-
Math
- 添加了
Math.log1p和Math.expm1。[Feature #21527]
- 添加了
-
Pathname
- Pathname 已从默认 gem 提升为 Ruby 的核心类。[Feature #17473]
-
Proc
Proc#parameters现在将匿名可选参数显示为[:opt]而不是[:opt, nil],使输出与匿名参数必需时保持一致。[Bug #20974]
-
Ractor
-
添加了
Ractor::Port类,用于在 Ractor 之间进行通信的新同步机制。[Feature #21262]port1 = Ractor::Port.new port2 = Ractor::Port.new Ractor.new port1, port2 do |port1, port2| port1 << 1 port2 << 11 port1 << 2 port2 << 12 end 2.times{ p port1.receive } #=> 1, 2 2.times{ p port2.receive } #=> 11, 12Ractor::Port提供了以下方法:Ractor::Port#receiveRactor::Port#send(或Ractor::Port#<<)Ractor::Port#closeRactor::Port#closed?
因此,
Ractor.yield和Ractor#take被移除。 -
添加了
Ractor#join和Ractor#value来等待 Ractor 终止。这些与Thread#join和Thread#value类似。 -
添加了
Ractor#monitor和Ractor#unmonitor作为内部使用的低级接口,用于实现Ractor#join。 -
Ractor.select现在只接受 Ractors 和 Ports。如果提供了 Ractors,则在 Ractor 终止时返回。 -
添加了
Ractor#default_port。每个Ractor都有一个默认端口,用于Ractor.send和Ractor.receive。 -
移除了
Ractor#close_incoming和Ractor#close_outgoing。 -
引入了
Ractor.shareable_proc和Ractor.shareable_lambda,以使 Proc 或 lambda 可共享。[Feature #21550]、[Feature #21557]
-
-
Range
-
Range#to_set现在执行长度检查,以防止出现无限范围问题。[Bug #21654] -
Range#overlap?现在能正确处理无限(无界)范围。[Bug #21185] -
修复了
Range#max在 beginless 整数范围上的行为。[Bug #21174] [Bug #21175]
-
-
Ruby
- 定义了一个新的顶层模块
Ruby,其中包含 Ruby 相关常量。该模块在 Ruby 3.4 中被保留,现在正式定义。[Feature #20884]
- 定义了一个新的顶层模块
-
Ruby::Box
- 一项新的(实验性)功能,用于提供定义的分离。有关“Ruby Box”的详细信息,请参阅 doc/language/box.md。[Feature #21311] [Misc #21385]
-
Set
-
Set现在是核心类,而不是一个自动加载的标准库类。[Feature #21216] -
Set#inspect现在使用更简单的显示方式,类似于字面量数组(例如,Set[1, 2, 3]而不是#<Set: {1, 2, 3}>)。[Feature #21389] -
将参数传递给
Set#to_set和Enumerable#to_set现在已被弃用。[Feature #21390]
-
-
Socket
Socket.tcp和TCPSocket.new接受open_timeout关键字参数来指定初始连接的超时时间。[Feature #21347]- 当
TCPSocket.new中发生用户指定的超时时,以前可能会根据情况抛出Errno::ETIMEDOUT或IO::TimeoutError。此行为已统一,现在始终抛出IO::TimeoutError。(请注意,在Socket.tcp中,当超时发生在操作系统级别时,仍有可能在类似情况下抛出Errno::ETIMEDOUT。)
-
String
-
更新 Unicode 至 17.0.0 版本和 Emoji 至 17.0 版本。[Feature #19908][Feature #20724][Feature #21275](也适用于 Regexp)
-
String#strip、strip!、lstrip、lstrip!、rstrip和rstrip!已扩展以接受*selectors参数。[Feature #21552]
-
-
Thread
- 引入了对
Thread#raise(cause:)参数的支持,类似于Kernel#raise。[Feature #21360]
- 引入了对
标准库更新
我们只列出值得注意的功能性标准库更改。
其他更改列在以下各节中。如果 Ruby 3.4.0 的发布历史记录有 GitHub 发布,我们也列出了之前的捆绑版本。
以下捆绑 gem 已从默认 gem 升级。
- ostruct 0.6.3
- pstore 0.2.0
- 0.1.4 至 v0.2.0
- benchmark 0.5.0
- logger 1.7.0
- rdoc 7.0.2
- win32ole 1.9.2
- 1.9.1 至 v1.9.2
- irb 1.16.0
- reline 0.6.3
- readline 0.0.4
- fiddle 1.1.8
添加了以下默认 gem。
- win32-registry 0.1.2
更新了以下默认 gem。
- RubyGems 4.0.3
- bundler 4.0.3
- date 3.5.1
- delegate 0.6.1
- digest 3.2.1
- 3.2.0 至 v3.2.1
- english 0.8.1
- 0.8.0 至 v0.8.1
- erb 6.0.1
- error_highlight 0.7.1
- etc 1.4.6
- fcntl 1.3.0
- 1.2.0 至 v1.3.0
- fileutils 1.8.0
- 1.7.3 至 v1.8.0
- forwardable 1.4.0
- 1.3.3 至 v1.4.0
- io-console 0.8.2
- 0.8.1 至 v0.8.2
- io-nonblock 0.3.2
- io-wait 0.4.0
- 0.3.2 至 v0.3.3,v0.3.5.test1,v0.3.5,v0.3.6,v0.4.0
- ipaddr 1.2.8
- json 2.18.0
- net-http 0.9.1
- openssl 4.0.0
- optparse 0.8.1
- pp 0.6.3
- 0.6.2 至 v0.6.3
- prism 1.7.0
- psych 5.3.1
- resolv 0.7.0
- stringio 3.2.0
- strscan 3.1.6
- time 0.4.2
- 0.4.1 至 v0.4.2
- timeout 0.6.0
- uri 1.1.1
- weakref 0.1.4
- 0.1.3 至 v0.1.4
- zlib 3.2.2
- 3.2.1 至 v3.2.2
更新了以下捆绑 gem。
- minitest 6.0.0
- power_assert 3.0.1
- rake 13.3.1
- test-unit 3.7.3
- rexml 3.4.4
- rss 0.3.2
- 0.3.1 至 0.3.2
- net-ftp 0.3.9
- 0.3.8 至 v0.3.9
- net-imap 0.6.2
- net-smtp 0.5.1
- 0.5.0 至 v0.5.1
- matrix 0.4.3
- 0.4.2 至 v0.4.3
- prime 0.1.4
- 0.1.3 至 v0.1.4
- rbs 3.10.0
- typeprof 0.31.1
- debug 1.11.1
- 1.11.0 至 v1.11.1
- base64 0.3.0
- 0.2.0 至 v0.3.0
- bigdecimal 4.0.1
- drb 2.2.3
- 2.2.1 至 v2.2.3
- syslog 0.3.0
- 0.2.0 至 v0.3.0
- csv 3.3.5
- repl_type_completor 0.1.12
RubyGems 和 Bundler
Ruby 4.0 捆绑了 RubyGems 和 Bundler 4 版本。请参阅以下链接了解详情。
- 升级到 RubyGems/Bundler 4 - RubyGems 博客
- 4.0.0 发布 - RubyGems 博客
- 4.0.1 发布 - RubyGems 博客
- 4.0.2 发布 - RubyGems 博客
- 4.0.3 发布 - RubyGems 博客
支持的平台
-
Windows
- 放弃支持 MSVC 版本早于 14.0 (_MSC_VER 1900) 的版本。这意味着现在需要 Visual Studio 2015 或更高版本。
兼容性问题
-
由于添加了
Ractor::Port,以下方法已从 Ractor 中移除:Ractor.yieldRactor#takeRactor#close_incomingRactor#close_outgoing
-
已弃用
ObjectSpace._id2ref。[Feature #15408] -
已移除
Process::Status#&和Process::Status#>>。它们在 Ruby 3.3 中已被弃用。[Bug #19868] -
已移除
rb_path_check。此函数用于$SAFE路径检查,该检查已在 Ruby 2.7 中移除,并且已弃用。[Feature #20971] -
“参数数量错误”的
ArgumentError的回溯现在将包含接收者的类或模块名称(例如,在Foo#bar中,而不是在bar中)。[Bug #21698] -
回溯不再显示
internal帧。这些方法现在看起来就像在 Ruby 源文件中的一样,与其他 C 实现的方法一致。[Bug #20968]之前
ruby -e '[1].fetch_values(42)' <internal:array>:211:in 'Array#fetch': index 42 outside of array bounds: -1...1 (IndexError) from <internal:array>:211:in 'block in Array#fetch_values' from <internal:array>:211:in 'Array#map!' from <internal:array>:211:in 'Array#fetch_values' from -e:1:in '<main>'之后
$ ruby -e '[1].fetch_values(42)' -e:1:in 'Array#fetch_values': index 42 outside of array bounds: -1...1 (IndexError) from -e:1:in '<main>'
标准库兼容性问题
-
CGI 库已从默认 gem 中移除。现在我们只为以下方法提供
cgi/escape:CGI.escape和CGI.unescapeCGI.escapeHTML和CGI.unescapeHTMLCGI.escapeURIComponent和CGI.unescapeURIComponentCGI.escapeElement和CGI.unescapeElement
-
随着
Set从 stdlib 移动到核心类,set/sorted_set.rb已被移除,SortedSet不再是自动加载的常量。请安装sorted_setgem 并require 'sorted_set'来使用SortedSet。 [Feature #21287] -
Net::HTTP
- 自动将
Content-Type标头设置为application/x-www-form-urlencoded的默认行为已被移除(针对带有正文的请求,例如POST,PUT,当该标头未显式设置时)。如果您的应用程序依赖于此自动默认行为,您的请求现在将不带 Content-Type 标头发送,这可能会破坏与某些服务器的兼容性。 [GH-net-http #205]
- 自动将
C API 更新
-
IO
rb_thread_fd_close已弃用,现在是空操作。如果您需要将文件描述符从 C 扩展公开到 Ruby 代码,请使用RUBY_IO_MODE_EXTERNAL创建一个IO实例,并使用rb_io_close(io)来关闭它(这还会中断并等待IO实例上所有挂起的操作)。直接关闭文件描述符不会中断挂起的操作,并可能导致未定义行为。换句话说,如果两个IO对象共享同一个文件描述符,关闭一个不会影响另一个。 [Feature #18455]
-
GVL
rb_thread_call_with_gvl现在有 GVL 和无 GVL 均可工作。这使得 gem 可以避免检查ruby_thread_has_gvl_p。请仍然注意 GVL。 [Feature #20750]
-
Set
-
为
Set添加了 C API。支持以下方法: [Feature #21459]rb_set_foreachrb_set_newrb_set_new_caparb_set_lookuprb_set_addrb_set_clearrb_set_deleterb_set_size
-
实现改进
Class#new(例如Object.new)在所有情况下都更快,尤其是在传递关键字参数时。这也被集成到 YJIT 和 ZJIT 中。 [Feature #21254]- 不同大小内存池的 GC 堆现在独立增长,当只有某些内存池包含长期存活的对象时,可以减少内存使用量。
- 大对象的页面上的 GC 扫描速度更快。
- “通用实例变量”对象(String、Array、
TypedData等)现在使用新的内部“fields”对象,以加快实例变量的访问速度。 - GC 会延迟维护内部
id2ref表,直到第一次使用时才开始,从而加快object_id分配和 GC 扫描的速度。 - Class 和 Module 对象上的
object_id和hash更快。 - 更大的 bignum Integer 可以通过可变宽度分配嵌入。
Random、Enumerator::Product、Enumerator::Chain、Addrinfo、StringScanner和一些内部对象现在受到写屏障保护,这降低了 GC 开销。
Ractor
为了使 Ractor 更稳定、更高效、更可用,进行了大量工作。这些改进使 Ractor 的实现更接近于脱离实验阶段。
- 性能改进
- 冻结的字符串和符号表内部使用无锁哈希集 [Feature #21268]
- 方法缓存查找在大多数情况下避免了锁定。
- 类(和通用实例变量)实例变量访问更快,并避免了锁定。
- 通过使用每个 Ractor 的计数器,在对象分配时避免了 CPU 缓存争用。
- 通过使用线程局部计数器,在 xmalloc/xfree 中避免了 CPU 缓存争用。
object_id在大多数情况下避免了锁定。
- 错误修复和稳定性
- 修复了在组合 Ractor 和 Threads 时可能出现的死锁。
- 修复了 Ractor 中 require 和 autoload 的问题。
- 修复了跨 Ractor 的编码/转码问题。
- 修复了 GC 操作和方法失效中的竞争条件。
- 修复了启动 Ractor 后进程 fork 的问题。
- GC 分配计数现在在 Ractor 下是准确的。
- 修复了 GC 后 TracePoints 不工作的[_Bug #19112_](https://bugs.ruby-lang.org/issues/19112)。
JIT
- ZJIT
- 引入了一个[实验性的基于方法的 JIT 编译器](https://docs.ruby-lang.org.cn/en/master/jit/zjit_md.html)。在可用时,可以通过
--zjit选项在运行时启用 ZJIT,或者通过调用RubyVM::ZJIT.enable来启用。构建 Ruby 时,需要 Rust 1.85.0 或更高版本才能包含 ZJIT 支持。 - 截至 Ruby 4.0.0,ZJIT 比解释器更快,但仍不如 YJIT 快。我们鼓励您尝试 ZJIT,但目前不建议在生产环境中使用它。
- 我们的目标是让 ZJIT 在 Ruby 4.1 中比 YJIT 更快且适合生产环境。
- 引入了一个[实验性的基于方法的 JIT 编译器](https://docs.ruby-lang.org.cn/en/master/jit/zjit_md.html)。在可用时,可以通过
- YJIT
RubyVM::YJIT.runtime_statsratio_in_yjit在默认构建中不再可用。请在configure时使用--enable-yjit=stats在--yjit-stats上启用它。- 向默认统计信息添加了
invalidate_everything,当所有代码都被 TracePoint 失效时,它会被递增。
- 向
RubyVM::YJIT.enable添加了mem_size:和call_threshold:选项。
- RJIT
--rjit已被移除。我们将第三方 JIT API 的实现转移到 [ruby/rjit 仓库](https://github.com/ruby/rjit)。
有关更多详细信息,请参阅 [NEWS](https://docs.ruby-lang.org.cn/en/v4.0.0/NEWS_md.html) 或 [commit logs](https://github.com/ruby/ruby/compare/v3_4_0...v4.0.0)。
通过这些更改,自 Ruby 3.4.0 以来,[3889 个文件已更改,230769 行插入,297003 行删除](https://github.com/ruby/ruby/compare/v3_4_0...v4.0.0#file_bucket)!
圣诞快乐,新年快乐,祝您使用 Ruby 4.0 编码愉快!
下载
-
https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.0.tar.gz
SIZE: 23955109 SHA1: 754e39e9ad122e1b6deaed860350bac133a35ed3 SHA256: 2e8389c8c072cb658c93a1372732d9eac84082c88b065750db1e52a5ac630271 SHA512: 688254e939b197d564e896fb951bc1abf07142f489e91c5ed0b11f68f52d6adb6b1f86616fe03f1f0bb434beeef7e75e158b9c616afb39bb34403b0b78d2ee19 -
https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.0.tar.xz
SIZE: 18008368 SHA1: 05ec670e86f84325c5353ef2f2888e53b6adc602 SHA256: a72bacee9de07283ebc19baa4ac243b193129f21aa4e168c7186fb1fe7d07fe1 SHA512: 2d5b2e566eaf70a5f3ea6ce6afc0611c0415de58a41336ef7a0b855c9a91eda9aa790a5f8b48e40a1eb9d50f8ea0f687216e617f16c8d040a08474f3116518a4 -
https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.0.zip
SIZE: 29253204 SHA1: 0b69f89d1d140157251c0d3a6032f6c45cdf81e8 SHA256: 70cb1bf89279b86ab9a975d504607c051fc05ee03e311d550a5541b65e373455 SHA512: a72e076ef618c0aeb9d20cf22e6fb12fda36809c0064ef0f98153b95a0bac257ef606342444a38f992c4594bf376a4d264686cf597463aa6f111220798784302
什么是 Ruby
Ruby 最初由 Matz (Yukihiro Matsumoto) 于 1993 年开发,现在作为开源项目进行开发。它运行在多个平台上,并在世界各地广泛使用,尤其是在 Web 开发领域。
近期新闻
Ruby 文档的全新外观
继 ruby-lang.org 重新设计之后,我们还有更多好消息来庆祝 Ruby 成立 30 周年:docs.ruby-lang.org 采用了 Aliki——RDoc 的新默认主题,焕然一新。
由 Stan Lo 发布于 2025 年 12 月 23 日
重新设计我们的网站标识
我们很高兴地宣布对我们的网站进行全面重新设计。此次更新的设计由 Akatsuka Taeko 创作。
由 Hiroshi SHIBATA 发布于 2025 年 12 月 22 日
Ruby 4.0.0 preview3 发布
我们很高兴地宣布 Ruby 4.0.0-preview3 的发布。Ruby 4.0 引入了 Ruby::Box 和“ZJIT”,并增加了许多改进。
由 naruse 发布于 2025 年 12 月 18 日
Ruby 3.4.8 发布
Ruby 3.4.8 已发布。
由 k0kubun 发布于 2025 年 12 月 17 日