NEWS for Ruby 3.2.0
本文档列出了自 3.1.0 版本以来用户可见的功能变更,不包括错误修复。
请注意,每个条目都保持得尽可能简洁,详情请参阅链接。
语言更改
-
匿名 rest 和 keyword rest 参数现在可以作为参数传递,而不仅仅是用于方法参数。 [Feature #18351]
def foo(*) bar(*) end def baz(**) quux(**) end
-
接受单个位置参数和关键字参数的 proc 不再会自动展平。 [Bug #18633]
proc{|a, **k| a}.call([1, 2]) # Ruby 3.1 and before # => 1 # Ruby 3.2 and after # => [1, 2]
-
在显式对象上设置常量的赋值求值顺序已与单属性赋值的求值顺序保持一致。使用此代码
foo::BAR = baz
foo现在在baz之前调用。同样,对于常量的多重赋值,使用从左到右的求值顺序。使用此代码foo1::BAR1, foo2::BAR2 = baz1, baz2
现在使用以下求值顺序
-
foo1 -
foo2 -
baz1 -
baz2
-
-
"Find pattern" 不再是实验性的。 [Feature #18585]
-
接受 rest 参数(如
*args)并希望通过foo(*args)委托关键字参数的方法现在必须用ruby2_keywords标记(如果尚未标记)。换句话说,所有希望通过*args委托关键字参数的方法现在都必须用ruby2_keywords标记,没有任何例外。这使得在库能够要求 Ruby 3+ 时更容易过渡到其他委托方式。以前,如果接收方法接受*args,则会保留ruby2_keywords标志,但这是一个错误和不一致。查找可能缺失的ruby2_keywords的一个好方法是运行测试套件,找到最后一个必须接收关键字参数的方法,在那里使用puts nil, caller, nil,并检查调用链中的每个必须委托关键字的方法/块是否正确标记为ruby2_keywords。 [Bug #18625] [Bug #16466]def target(**kw) end # Accidentally worked without ruby2_keywords in Ruby 2.7-3.1, ruby2_keywords # needed in 3.2+. Just like (*args, **kwargs) or (...) would be needed on # both #foo and #bar when migrating away from ruby2_keywords. ruby2_keywords def bar(*args) target(*args) end ruby2_keywords def foo(*args) bar(*args) end foo(k: 1)
核心类更新
注意:此处仅列出重要的类更新。
-
-
引入
Fiber.[]和Fiber.[]=用于可继承的 fiber 存储。引入Fiber#storage和Fiber#storage=(实验性)用于获取和重置当前存储。引入Fiber.new(storage:)用于在创建 fiber 时设置存储。 [Feature #19078]现有的
Thread和Fiber局部变量可能难以使用。线程局部变量在所有 fiber 之间共享,难以隔离,而 fiber 局部变量可能难以共享。通常希望定义一个执行单元(“执行上下文”),以便某些状态在该上下文中创建的所有 fiber 和线程之间共享。这就是Fiber存储所提供的。def log(message) puts "#{Fiber[:request_id]}: #{message}" end def handle_requests while request = read_request Fiber.schedule do Fiber[:request_id] = SecureRandom.uuid request.messages.each do |message| Fiber.schedule do log("Handling #{message}") # Log includes inherited request_id. end end end end end
您通常应该考虑为任何您希望在给定上下文中的所有 fiber 和线程之间隐式共享的状态使用
Fiber存储,例如连接池、请求 ID、日志级别、环境变量、配置等。
-
-
-
引入
Fiber::Scheduler#io_select以实现非阻塞IO.select。 [Feature #19060]
-
-
-
引入
IO#timeout=和IO#timeout,如果阻塞操作超过指定超时时间,可能会引发IO::TimeoutError。 [Feature #18630]STDIN.timeout = 1 STDIN.read # => Blocking operation timed out! (IO::TimeoutError)
-
引入
IO.new(..., path:)并将File#path提升到IO#path。 [Feature #19036]
-
-
Class
-
Class#attached_object,它返回接收者是单例类的对象。如果接收者不是单例类,则引发TypeError。 [Feature #12084]class Foo; end Foo.singleton_class.attached_object #=> Foo Foo.new.singleton_class.attached_object #=> #<Foo:0x000000010491a370> Foo.attached_object #=> TypeError: `Foo' is not a singleton class nil.singleton_class.attached_object #=> TypeError: `NilClass' is not a singleton class
-
-
-
新的核心类,用于表示简单的不可变值对象。该类类似于
Struct,并部分共享实现,但具有更精简和严格的 API。 [Feature #16122]Measure = Data.define(:amount, :unit) distance = Measure.new(100, 'km') #=> #<data Measure amount=100, unit="km"> weight = Measure.new(amount: 50, unit: 'kg') #=> #<data Measure amount=50, unit="kg"> weight.with(amount: 40) #=> #<data Measure amount=40, unit="kg"> weight.amount #=> 50 weight.amount = 40 #=> NoMethodError: undefined method `amount='
-
-
-
Encoding#replicate 已被弃用,将在 3.3 中删除。 [Feature #18949]
-
占位符编码
Encoding::UTF_16和Encoding::UTF_32不再尝试根据字节顺序标记动态猜测字节序。请改用Encoding::UTF_16BE/UTF_16LE和Encoding::UTF_32BE/UTF_32LE。此更改加快了获取String编码的速度。 [Feature #18949] -
将最大编码集大小限制为 256。如果超出最大大小,将引发
EncodingError。 [Feature #18949]
-
-
-
已添加
Enumerator.product。Enumerator::Product是实现。 [Feature #18685]
-
-
-
已添加
Exception#detailed_message。默认错误打印程序调用此方法来处理Exception对象而不是消息。 [Feature #18564]
-
-
-
Hash#shift在哈希为空时现在始终返回 nil,而不是返回默认值或调用默认 proc。 [Bug #16908]
-
-
-
已添加
Integer#ceildiv。 [Feature #18809]
-
-
-
Kernel#binding如果从非 Ruby 帧(例如 C 中定义的方法)调用,则会引发RuntimeError。 [Bug #18487]
-
-
Module
-
-
Proc#dup返回子类的实例。 [Bug #17545] -
Proc#parameters现在接受 lambda 关键字。 [Feature #15357]
-
-
Process
-
为 FreeBSD 平台添加了
RLIMIT_NPTS常量
-
-
-
引入了基于缓存的优化。许多(但不是全部)
Regexp匹配现在是线性时间,这将防止正则表达式拒绝服务(ReDoS)漏洞。 [Feature #19104] -
Regexp.new现在支持将正则表达式标志作为Integer或String传递。未知标志将引发ArgumentError。否则,任何不是true、false、nil或Integer的值都将发出警告。 [Feature #18788] -
已添加
Regexp.timeout=。此外,Regexp.new现在支持 timeout 关键字。请参阅 [Feature #17837]
-
-
-
已添加 Refinement#refined_class。 [Feature #12737]
-
-
-
为
parse、parse_file和of添加了error_tolerant选项。 [Feature #19013] 使用此选项-
SyntaxError被抑制 -
为无效输入返回 AST
-
当解析器到达输入末尾但
end不足时,会补全end -
end根据缩进被视为关键字
# Without error_tolerant option root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY) def m a = 10 if end RUBY # => <internal:ast>:33:in `parse': syntax error, unexpected `end' (SyntaxError) # With error_tolerant option root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true) def m a = 10 if end RUBY p root # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-4:3> # `end` is treated as keyword based on indent root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true) module Z class Foo foo. end def bar end end RUBY p root.children[-1].children[-1].children[-1].children[-2..-1] # => [#<RubyVM::AbstractSyntaxTree::Node:CLASS@2:2-4:5>, #<RubyVM::AbstractSyntaxTree::Node:DEFN@6:2-7:5>]
-
-
为
parse、parse_file和of添加了keep_tokens选项。为RubyVM::AbstractSyntaxTree::Node添加了 tokens 和 all_tokens。 [Feature #19070]root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2", keep_tokens: true) root.tokens # => [[0, :tIDENTIFIER, "x", [1, 0, 1, 1]], [1, :tSP, " ", [1, 1, 1, 2]], ...] root.tokens.map{_1[2]}.join # => "x = 1 + 2"
-
-
Set
-
Set 现在可作为内置类使用,无需
require "set"。 [Feature #16989] 它目前通过 Set 常量或调用Enumerable#to_set进行自动加载。
-
-
-
更新 Unicode 到 15.0.0 版本和 Emoji 版本 15.0。 [Feature #18639] (也适用于
Regexp) -
已添加
String#bytesplice。 [Feature #18598] -
已添加
String#dedup作为String#-@的别名。 [Feature #18595]
-
-
现在可以在没有
keyword_init: true的情况下使用关键字参数初始化Struct类,即使在Struct.new上也是如此。 [Feature #16806]Post = Struct.new(:id, :name) Post.new(1, "hello") #=> #<struct Post id=1, name="hello"> # From Ruby 3.2, the following code also works without keyword_init: true. Post.new(id: 1, name: "hello") #=> #<struct Post id=1, name="hello">
-
-
-
已添加
Thread::Queue#pop(timeout: sec)。 [Feature #18774]
-
-
-
已添加
Thread::SizedQueue#pop(timeout: sec)。 [Feature #18774] -
已添加
Thread::SizedQueue#push(timeout: sec)。 [Feature #18944]
-
-
-
已添加
Time#deconstruct_keys,允许在模式匹配表达式中使用Time实例。 [Feature #19071] -
Time.new现在可以解析像Time#inspect生成的字符串,并返回基于给定参数的Time实例。 [Feature #18033]
-
-
-
已添加
SyntaxError#path。 [Feature #19138]
-
-
-
TracePoint#binding对于c_call/c_returnTracePoints 现在返回nil。 [Bug #18487] -
当给出块且未传递
target和target_line关键字参数时,TracePoint#enable的target_thread关键字参数现在默认为当前线程。 [Bug #16889]
-
-
-
UnboundMethod#==如果实际方法相同,则返回true。例如,String.instance_method(:object_id) == Array.instance_method(:object_id)返回true。 [Feature #18798] -
UnboundMethod#inspect不显示instance_method的接收者。例如String.instance_method(:object_id).inspect返回"#<UnboundMethod: Kernel#object_id()>"(之前是"#<UnboundMethod: String(Kernel)#object_id()>")。
-
-
-
通过
GC.latest_gc_info暴露need_major_gc。 GH-6791
-
-
-
ObjectSpace.dump_all也转储形状。 GH-6868
-
标准库更新
-
-
向 bundle gem 添加了 --ext=rust 支持,用于创建带有 Rust 扩展的简单 gem。 [GH-rubygems-6149]
-
加快克隆 git 仓库的速度 [GH-rubygems-4475]
-
RubyGems
-
为 cargo builder 添加了 mswin 支持。 [GH-rubygems-6167]
-
-
-
Coverage.setup现在接受eval: true。通过此,eval和相关方法能够生成代码覆盖率。 [Feature #19008] -
Coverage.supported?(mode)启用对支持哪些覆盖率模式的检测。 [Feature #19026]
-
-
-
添加了
Date#deconstruct_keys和DateTime#deconstruct_keys,与 [Feature #19071] 相同。
-
-
-
ERB::Util.html_escape比CGI.escapeHTML更快。 -
使用
CGI.escapeURIComponent使ERB::Util.url_encode更快。 -
从
erb命令中删除了-S选项。
-
-
-
添加了
FileUtils.ln_sr方法和relative:选项到FileUtils.ln_s。 [Feature #18925]
-
-
IRB
-
添加了 debug.gem 集成命令:
debug,break,catch,next,delete,step,continue,finish,backtrace,info-
即使您的 Gemfile 中没有
gem "debug",这些命令也能正常工作。 -
另请参阅:Ruby 3.2 的 IRB 新特性?
-
-
添加了更多类似 Pry 的命令和功能。
-
添加了
edit和show_cmds(类似 Pry 的help)。 -
ls接受-g或-G选项以过滤输出。 -
show_source是$的别名,并接受未加引号的输入。 -
whereami是@的别名。
-
-
-
Net::Protocol
-
提高了
Net::BufferedIO的性能。 [GH-net-protocol-14]
-
-
-
添加了
Pathname#lutime。 [GH-pathname-20]
-
-
-
为支持的平台添加了以下常量。
-
SO_INCOMING_CPU -
SO_INCOMING_NAPI_ID -
SO_RTABLE -
SO_SETFIB -
SO_USER_COOKIE -
TCP_KEEPALIVE -
TCP_CONNECTION_INFO
-
-
-
-
以前的
dead_end功能 syntax_suggest 已集成到 Ruby 中。 [Feature #18159]
-
-
-
添加了对 Windows 上
UNIXSocket的支持。模拟匿名套接字。在可能的情况下,添加了对File.socket?和File::Stat#socket?的支持。 [Feature #19135]
-
-
更新了以下默认 gem。
-
RubyGems 3.4.1
-
abbrev 0.1.1
-
benchmark 0.2.1
-
bigdecimal 3.1.3
-
bundler 2.4.1
-
cgi 0.3.6
-
csv 3.2.6
-
date 3.3.3
-
delegate 0.3.0
-
did_you_mean 1.6.3
-
digest 3.1.1
-
drb 2.1.1
-
english 0.7.2
-
erb 4.0.2
-
error_highlight 0.5.1
-
etc 1.4.2
-
fcntl 1.0.2
-
fiddle 1.1.1
-
fileutils 1.7.0
-
forwardable 1.3.3
-
getoptlong 0.2.0
-
io-console 0.6.0
-
io-nonblock 0.2.0
-
io-wait 0.3.0
-
ipaddr 1.2.5
-
irb 1.6.2
-
json 2.6.3
-
logger 1.5.3
-
mutex_m 0.1.2
-
net-http 0.3.2
-
net-protocol 0.2.1
-
nkf 0.1.2
-
open-uri 0.3.0
-
open3 0.1.2
-
openssl 3.1.0
-
optparse 0.3.1
-
ostruct 0.5.5
-
pathname 0.2.1
-
pp 0.4.0
-
pstore 0.1.2
-
psych 5.0.1
-
racc 1.6.2
-
rdoc 6.5.0
-
readline-ext 0.1.5
-
reline 0.3.2
-
resolv 0.2.2
-
resolv-replace 0.1.1
-
securerandom 0.2.2
-
set 1.0.3
-
stringio 3.0.4
-
strscan 3.0.5
-
syntax_suggest 1.0.2
-
syslog 0.1.1
-
tempfile 0.1.3
-
time 0.2.1
-
timeout 0.3.1
-
tmpdir 0.1.3
-
tsort 0.1.1
-
un 0.2.1
-
uri 0.12.0
-
weakref 0.1.2
-
win32ole 1.8.9
-
yaml 0.2.1
-
zlib 3.0.0
-
-
以下捆绑 gem 已更新。
-
minitest 5.16.3
-
power_assert 2.0.3
-
test-unit 3.5.7
-
net-ftp 0.2.0
-
net-imap 0.3.4
-
net-pop 0.1.2
-
net-smtp 0.3.3
-
rbs 2.8.2
-
typeprof 0.21.3
-
debug 1.7.1
-
有关默认 gem 或捆绑 gem 的详细信息,请参阅 GitHub 发布(例如 Logger 的 GitHub Releases)或更改日志。
支持的平台
-
添加了 WebAssembly/WASI。有关更多详细信息,请参阅 wasm/README.md 和 ruby.wasm。 [Feature #18462]
兼容性问题
-
String#to_c目前将一系列下划线视为Complex字符串的结尾。 [Bug #19087] -
现在
ENV.clone和ENV.dup一样都会引发TypeError。 [Bug #17767]
已删除的常量
已删除以下已弃用的常量。
-
Fixnum和Bignum[Feature #12005] -
Random::DEFAULT[Feature #17351] -
Struct::Group -
Struct::Passwd
已删除的方法
已删除以下已弃用的方法。
-
Dir.exists?[Feature #17391] -
File.exists?[Feature #17391] -
Kernel#=~[Feature #15231] -
Kernel#taint,Kernel#untaint,Kernel#tainted?[Feature #16131] -
Kernel#trust,Kernel#untrust,Kernel#untrusted?[Feature #16131] -
Method#public?,Method#private?,Method#protected?,UnboundMethod#public?,UnboundMethod#private?,UnboundMethod#protected?[Bug #18729] [Bug #18751] [Bug #18435]
扩展库的源代码不兼容
-
扩展库提供了 PRNG,
Random的子类需要更新。有关更多信息,请参阅下面的 [PRNG 更新]。 [Bug #19100]
错误打印程序
-
Ruby 不再转义错误消息中的控制字符和反斜杠。 [Feature #18367]
定义类/模块时的常量查找
-
在 Ruby 3.1 或更早版本中,当通过类/模块语句直接在
Object类下定义类/模块时,如果已存在同名的通过Module#include定义的类/模块,则该语句将被视为“开放类”。从 Ruby 3.2 开始,将定义一个新类。 [Feature #18832]
标准库兼容性问题
-
Psych不再捆绑 libyaml 源代码。此外,Fiddle 也不再捆绑 libffi 源代码。用户需要通过 apt、yum、brew 等包管理器自行安装 libyaml/libffi 库。Psych和 fiddle 支持使用特定版本的 libyaml 和 libffi 源代码进行静态构建。您可以使用以下方法构建带有 libyaml-0.2.5 的 psych。$ ./configure --with-libyaml-source-dir=/path/to/libyaml-0.2.5
您可以使用以下方法构建带有 libffi-3.4.4 的 fiddle。
$ ./configure --with-libffi-source-dir=/path/to/libffi-3.4.4
-
检查
CGI::Cookie中的 cookie 名称/路径/域字符。 [CVE-2021-33621] -
URI.parse在 host 中返回空字符串而不是 nil。 [sec-156615]
C API 更新
更新的 C API
以下 API 已更新。
-
PRNG 更新
ruby/random.h中的rb_random_interface_t已更新并进行了版本控制。使用此接口且为旧版本构建的扩展库需要重新构建,并添加init_int32函数。
新增 C API
-
添加了
VALUE rb_hash_new_capa(long capa)以创建具有所需容量的哈希。 -
添加了
rb_internal_thread_add_event_hook和rb_internal_thread_add_event_hook以对线程调度进行检测。以下事件可用-
RUBY_INTERNAL_THREAD_EVENT_STARTED -
RUBY_INTERNAL_THREAD_EVENT_READY -
RUBY_INTERNAL_THREAD_EVENT_RESUMED -
RUBY_INTERNAL_THREAD_EVENT_SUSPENDED -
RUBY_INTERNAL_THREAD_EVENT_EXITED
-
-
为调试器添加了
rb_debug_inspector_current_depth和rb_debug_inspector_frame_depth。
已移除的 C API
已删除以下已弃用的 API。
-
rb_cData变量。 -
“taintedness”和“trustedness”函数。 [Feature #16131]
实现改进
-
修复了
Kernel#autoload中的几个竞态条件。 [Bug #18782] -
引用常量表达式的缓存无效化现在更加细粒化。移除了
RubyVM.stat(:global_constant_state),因为它与之前的缓存方案紧密相关,在该方案中,设置任何常量都会使系统中所有缓存无效。引入了新的键:constant_cache_invalidations和:constant_cache_misses来帮助处理:global_constant_state的用例。 [Feature #18589] -
引入了
Regexp匹配的基于缓存的优化。 [Feature #19104] -
可变宽度分配现已默认启用。 [Feature #18239]
-
添加了一个新的实例变量缓存机制,称为对象形状,它提高了大多数对象的内联缓存命中率,并允许我们生成非常高效的 JIT 代码。实例变量以一致顺序定义的对象的性能提升最为显著。 [Feature #18776]
-
通过使用位图查找“可标记”对象来加速指令序列的标记。此更改导致更快的重大垃圾回收。 [Feature #18875]
JIT
YJIT
-
YJIT 不再是实验性的
-
已经在生产工作负载上测试了一年多,并被证明相当稳定。
-
-
YJIT 现在支持 Linux、MacOS、BSD 和其他 UNIX 平台上的 x86-64 和 arm64/aarch64 CPU。
-
本次发布增加了对 Mac M1/M2、AWS Graviton 和 Raspberry Pi 4 的支持。
-
-
构建 YJIT 现在需要 Rust 1.58.0+。 [Feature #18481]
-
为了确保 CRuby 是用 YJIT 构建的,请在运行
./configure之前安装rustc>= 1.58.0。 -
如果您遇到任何问题,请联系 YJIT 团队。
-
-
JIT 代码的物理内存是惰性分配的。与 Ruby 3.1 不同,Ruby 进程的 RSS 被最小化,因为由
--yjit-exec-mem-size分配的虚拟内存页直到被 JIT 代码实际使用时才会被映射到物理内存页。 -
引入代码
GC,当 JIT 代码的内存消耗达到--yjit-exec-mem-size时,它会释放所有代码页面。-
RubyVM::YJIT.runtime_stats除了现有的inline_code_size和outlined_code_size键之外,还返回了代码GC指标:code_gc_count、live_page_count、freed_page_count和freed_code_size。
-
-
由
RubyVM::YJIT.runtime_stats产生的大部分统计数据现在在发行版本中可用。-
只需使用
--yjit-stats运行 ruby 即可计算和转储统计数据(会产生一些运行时开销)。
-
-
YJIT 现在已针对利用对象形状进行了优化。 [Feature #18776]
-
利用更细粒度的常量无效化,在定义新常量时使更少的代码无效。 [Feature #18589]
-
默认
--yjit-exec-mem-size已更改为 64 (MiB)。 -
默认
--yjit-call-threshold已更改为 30。
MJIT
-
MJIT 编译器已在 Ruby 中重新实现为
ruby_vm/mjit/compiler。 -
MJIT 编译器在分叉的 Ruby 进程下执行,而不是在一个称为 MJIT 工作线程的原生线程中执行。 [Feature #18968]
-
因此,不再支持 Microsoft Visual Studio (MSWIN)。
-
-
不再支持 MinGW。 [Feature #18824]
-
将
--mjit-min-calls重命名为--mjit-call-threshold。 -
将默认
--mjit-max-cache从 10000 改回 100。