NEWS for Ruby 3.2.0¶ ↑
本文件列出了自 3.1.0 版本发布以来的用户可见功能变更,不包括错误修复。
请注意,每个条目都保持在最小限度,详细信息请参阅链接。
语言变更¶ ↑
-
现在可以将匿名剩余参数和关键字剩余参数作为参数传递,而不仅仅是在方法参数中使用。 [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
-
-
"查找模式"不再是实验性的。 [Feature #18585]
-
接受剩余参数(如
*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、记录器级别、环境变量、配置等。
-
-
-
引入
IO#timeout=
和IO#timeout
,如果阻塞操作超过指定超时时间,它们会导致IO::TimeoutError
被抛出。[功能 #18630]STDIN.timeout = 1 STDIN.read # => Blocking operation timed out! (IO::TimeoutError)
-
引入 `IO.new(..., path:)` 并将 `File#path` 提升为 `IO#path`。[功能 #19036]
-
-
-
Class#attached_object
,它返回接收者是单例类的对象。如果接收者不是单例类,则会抛出TypeError
。[功能 #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。[功能 #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='
-
-
-
Enumerator.product
已添加。Enumerator::Product
是实现。[功能 #18685]
-
-
-
Exception#detailed_message
已添加。默认错误打印机在Exception
对象上调用此方法,而不是消息。[功能 #18564]
-
-
-
Hash#shift
现在如果哈希为空,则始终返回 nil,而不是返回默认值或调用默认 proc。[错误 #16908]
-
-
-
添加了
Integer#ceildiv
。[功能 #18809]
-
-
-
如果从非 Ruby 帧(例如在 C 中定义的方法)调用
Kernel#binding
,它将引发RuntimeError
。[错误 #18487]
-
-
-
Proc#parameters
现在接受 lambda 关键字。[功能 #15357]
-
-
在 FreeBSD 平台上添加了
RLIMIT_NPTS
常量
-
-
-
引入了基于缓存的优化。许多(但并非全部)
Regexp
匹配现在是线性时间的,这将防止正则表达式拒绝服务 (ReDoS) 漏洞。[功能 #19104] -
引入了
Regexp.linear_time?
。[功能 #19194] -
Regexp.new
现在支持将正则表达式标志传递为Integer
,也支持传递为String
。未知标志将引发ArgumentError
。否则,除了true
、false
、nil
或Integer
之外的任何内容都会发出警告。[功能 #18788] -
添加了
Regexp.timeout=
。此外,Regexp.new
现在支持 timeout 关键字。参见 [功能 #17837]
-
-
-
添加了 Refinement#refined_class。[功能 #12737]
-
-
-
为
parse
、parse_file
和of
添加error_tolerant
选项。[功能 #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
。[功能 #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"
-
-
集合
-
集合现在可以作为内置类使用,无需
require "set"
。[功能 #16989] 它目前通过 Set 常量或对Enumerable#to_set
的调用自动加载。
-
-
-
将 Unicode 更新至版本 15.0.0,将 Emoji 更新至版本 15.0。[功能 #18639](也适用于
Regexp
) -
已添加
String#bytesplice
。[功能 #18598] -
已添加
String#dedup
作为String#-@
的别名。[功能 #18595]
-
-
Struct
类也可以使用关键字参数进行初始化,而无需在Struct.new
上使用keyword_init: true
。[功能 #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)。[功能 #18774]
-
-
-
已添加
Thread::SizedQueue#pop
(timeout: sec)。[功能 #18774] -
已添加
Thread::SizedQueue#push
(timeout: sec)。[功能 #18944]
-
-
-
已添加
Time#deconstruct_keys
,允许在模式匹配表达式中使用Time
实例。[功能 #19071] -
现在,
Time.new
可以解析由Time#inspect
生成的字符串,并根据给定的参数返回Time
实例。[功能 #18033]
-
-
-
添加了 SyntaxError#path。[功能 #19138]
-
-
-
TracePoint#binding
现在对于c_call
/c_return
TracePoint 返回nil
。[Bug #18487] -
TracePoint#enable
的target_thread
关键字参数现在默认设置为当前线程,如果给出了一个代码块并且没有传递target
和target_line
关键字参数。[Bug #16889]
-
-
-
如果实际方法相同,
UnboundMethod#==
返回true
。例如,String.instance_method(:object_id) == Array.instance_method(:object_id)
返回true
。[功能 #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
-
标准库更新¶ ↑
-
Bundler
-
为 bundle gem 添加 --ext=rust 支持,用于创建带有 Rust 扩展的简单 gem。[GH-rubygems-6149]
-
使克隆 git 仓库更快 [GH-rubygems-4475]
-
RubyGems
-
为 cargo builder 添加 mswin 支持。[GH-rubygems-6167]
-
-
CGI
-
添加了
CGI.escapeURIComponent
和CGI.unescapeURIComponent
。[功能 #18822]
-
-
Coverage
-
Date
-
添加了
Date#deconstruct_keys
和DateTime#deconstruct_keys
,与 [功能 #19071]
-
-
ERB
-
FileUtils
-
添加 FileUtils.ln_sr 方法和 FileUtils.ln_s 的
relative:
选项。[功能 #18925]
-
-
IRB
-
添加了 debug.gem 集成命令:
debug
、break
、catch
、next
、delete
、step
、continue
、finish
、backtrace
、info
-
即使你的 Gemfile 中没有
gem "debug"
,它们也能正常工作。
-
-
添加了更多类似 Pry 的命令和功能。
-
添加了
edit
和show_cmds
(类似于 Pry 的help
)。 -
ls
接受-g
或-G
选项来过滤输出。 -
show_source
是$
的别名,并接受未引用的输入。 -
whereami
是@
的别名。
-
-
-
Net::Protocol
-
提高
Net::BufferedIO
的性能。[GH-net-protocol-14]
-
-
Pathname
-
添加了
Pathname#lutime
。[GH-pathname-20]
-
-
Socket
-
为支持的平台添加了以下常量。
-
SO_INCOMING_CPU
-
SO_INCOMING_NAPI_ID
-
SO_RTABLE
-
SO_SETFIB
-
SO_USER_COOKIE
-
TCP_KEEPALIVE
-
TCP_CONNECTION_INFO
-
-
-
SyntaxSuggest
-
syntax_suggest
(以前称为dead_end
)的功能已集成到 Ruby 中。[功能 #18159]
-
-
UNIXSocket
-
添加了对 Windows 上 UNIXSocket 的支持。模拟匿名套接字。添加了对
File.socket?
和File::Stat#socket?
的支持(如果可能)。[功能 #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
-
摘要 3.1.1
-
drb 2.1.1
-
英语 0.7.2
-
erb 4.0.2
-
error_highlight 0.5.1
-
等等 1.4.2
-
fcntl 1.0.2
-
小提琴 1.1.1
-
文件工具 1.7.0
-
可转发 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
-
记录器 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
-
路径名 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
-
设置 1.0.3
-
stringio 3.0.4
-
strscan 3.0.5
-
语法建议 1.0.2
-
syslog 0.1.1
-
tempfile 0.1.3
-
时间 0.2.1
-
超时 0.3.1
-
tmpdir 0.1.3
-
tsort 0.1.1
-
un 0.2.1
-
uri 0.12.0
-
弱引用 0.1.2
-
win32ole 1.8.9
-
yaml 0.2.1
-
zlib 3.0.0
-
-
以下捆绑的宝石已更新。
-
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
-
调试 1.7.1
-
有关默认宝石或捆绑宝石的详细信息,请参阅 GitHub 版本,例如 GitHub 版本的记录器 或更改日志。
支持的平台¶ ↑
-
添加了 WebAssembly/WASI。有关更多详细信息,请参阅 wasm/README.md 和 ruby.wasm。[功能 #18462]
兼容性问题¶ ↑
-
现在
ENV.clone
除了ENV.dup
之外还会引发TypeError
[错误 #17767]
已删除的常量¶ ↑
以下已弃用的常量已删除。
已移除方法¶ ↑
以下已弃用方法已被移除。
-
Dir.exists?
[功能 #17391] -
File.exists?
[功能 #17391] -
Kernel#=~
[功能 #15231] -
Kernel#taint
,Kernel#untaint
,Kernel#tainted?
[功能 #16131] -
Kernel#trust
,Kernel#untrust
,Kernel#untrusted?
[功能 #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 不再对错误消息中的控制字符和反斜杠进行转义。[功能 #18367]
定义类/模块时的常量查找¶ ↑
-
当通过类/模块语句在
Object
类下直接定义类/模块时,如果已经通过Module#include
定义了相同名称的类/模块,则该语句在 Ruby 3.1 或之前版本中被视为“打开类”。从 Ruby 3.2 开始,将定义一个新的类。[功能 #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
返回主机中的空字符串而不是 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 现在经过优化以利用对象形状。[功能 #18776]
-
利用更细粒度的常量失效来减少定义新常量时失效的代码量。[功能 #18589]
-
默认的
--yjit-exec-mem-size
更改为 64(MiB)。 -
默认的
--yjit-call-threshold
更改为 30。