NEWS for Ruby 3.2.0¶ ↑
此文档列出了自 3.1.0 版本发布以来用户可见的功能变更,不包括错误修复。
请注意,每条变更都尽可能简短,请参阅链接以获取详细信息。
语言变更¶ ↑
-
匿名 rest 和关键字 rest 参数现在可以作为参数传递,而不仅仅是在方法参数中使用。[功能 #18351]
def foo(*) bar(*) end def baz(**) quux(**) end
-
接受单个位置参数和关键字的 proc 将不再自动展开。[错误 #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
-
-
"查找模式" 不再是实验性的。[功能 #18585]
-
采用 rest 参数(如
*args
)并希望通过foo(*args)
委派关键字参数的方法现在必须标记为ruby2_keywords
(如果不是这种情况)。换句话说,所有希望通过*args
委派关键字参数的方法现在都必须标记为ruby2_keywords
,无一例外。一旦库可以要求 Ruby 3+,这将使过渡到其他委派方式变得更容易。以前,如果接收方法采用*args
,则保留ruby2_keywords
标志,但这是一个错误和不一致。查找可能缺少的ruby2_keywords
的一个好技术是运行测试套件,在测试套件失败的地方找到必须接收关键字参数的最后一个方法,在那里使用puts nil, caller, nil
,并检查调用链上的每个方法/块,这些方法/块必须委派关键字并正确标记为ruby2_keywords
。[错误 #18625] [错误 #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 时设置存储。[功能 #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
存储,例如连接池、请求 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='
-
-
-
Exception#detailed_message
已添加。默认错误打印机在Exception
对象上调用此方法,而不是 message。[特性 #18564]
-
-
-
Hash#shift
现在如果哈希为空,则始终返回 nil,而不是返回默认值或调用默认 proc。[错误 #16908]
-
-
-
Integer#ceildiv
已添加。[特性 #18809]
-
-
-
Kernel#binding
如果从非 Ruby 帧(例如用 C 定义的方法)调用,则会引发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
现在支持超时关键字。请参阅 [功能 #17837]
-
-
-
为
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"
-
-
-
Set
现在可用作内置类,无需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.each_caller_location
。[特性 #16663]
-
-
-
添加了
Thread::Queue#pop
(timeout: sec)。[特性 #18774]
-
-
-
添加了
SyntaxError#path
。[特性 #19138]
-
-
-
如果实际方法相同,
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
-
标准库更新¶ ↑
-
-
为 bundle gem 添加 --ext=rust 支持,以便使用 Rust 扩展创建简单的 gem。[GH-rubygems-6149]
-
加快克隆 git 仓库的速度 [GH-rubygems-4475]
-
RubyGems
-
为 cargo 构建器添加 mswin 支持。[GH-rubygems-6167]
-
-
-
添加了
CGI.escapeURIComponent
和CGI.unescapeURIComponent
。[功能 #18822]
-
-
-
添加了
Date#deconstruct_keys
和DateTime#deconstruct_keys
,与 [功能 #19071] 相同
-
-
-
添加了
FileUtils.ln_sr
方法和relative:
选项到FileUtils.ln_s
。[功能 #18925]
-
-
-
添加了 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#lutime
。[GH-pathname-20]
-
-
-
为受支持平台添加以下常量。
-
SO_INCOMING_CPU
-
SO_INCOMING_NAPI_ID
-
SO_RTABLE
-
SO_SETFIB
-
SO_USER_COOKIE
-
TCP_KEEPALIVE
-
TCP_CONNECTION_INFO
-
-
-
-
Ruby 集成了
syntax_suggest
(前身为dead_end
)功能。[功能 #18159]
-
-
-
在 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
-
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
-
请参阅 GitHub 版本,例如 Logger 的 GitHub 版本 或变更日志,了解默认 gem 或捆绑 gem 的详细信息。
支持的平台¶ ↑
-
已添加 WebAssembly/WASI。请参阅 wasm/README.md 和 ruby.wasm 了解更多详情。[功能 #18462]
兼容性问题¶ ↑
-
现在
ENV.clone
会引发TypeError
,以及ENV.dup
[错误 #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?
[错误 #18729] [错误 #18751] [错误 #18435]
扩展库的源代码不兼容性¶ ↑
错误打印机¶ ↑
-
Ruby 不再转义错误消息中的控制字符和反斜杠。[功能 #18367]
定义类/模块时常量查找¶ ↑
-
在
Object
类下直接使用类/模块语句定义类/模块时,如果已经通过Module#include
定义了同名类/模块,则在 Ruby 3.1 或更早版本中,该语句被视为“打开类”,自 Ruby 3.2 起,则定义新类。[功能 #18832]
Stdlib 兼容性问题¶ ↑
-
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”函数。[功能 #16131]
实现改进¶ ↑
-
修复了
Kernel#autoload
中的几个竞争条件。[错误 #18782] -
引用常量的表达式的缓存失效现在更加细化。
RubyVM.stat(:global_constant_state)
已被移除,因为它与以前的缓存方案密切相关,其中设置任何常量都会使系统中的所有缓存失效。引入了新键:constant_cache_invalidations
和:constant_cache_misses
,以帮助使用:global_constant_state
的用例。[功能 #18589] -
添加了一个新的实例变量缓存机制,称为对象形状,它改善了大多数对象的内联缓存命中,并允许我们生成非常高效的 JIT 代码。实例变量以一致顺序定义的对象将获得最大的性能优势。[功能 #18776]
-
使用位图查找“可标记”对象来加速标记指令序列。此更改导致更快的主要收集。[功能 #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+。[功能 #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
返回代码GC
指标,除了现有的inline_code_size
和outlined_code_size
键之外: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。