NEWS for Ruby 2.7.0¶ ↑
本文件列出了版本发布之间用户可见的功能变更,不包括错误修复。
请注意,每个条目都非常简短,没有提供任何原因或参考信息。要获取包含所有充分信息的完整变更列表,请参阅 ChangeLog 文件或 Redmine(例如 https://bugs.ruby-lang.org/issues/$FEATURE_OR_BUG_NUMBER
)。
自 2.6.0 版本以来的变更¶ ↑
语言变更¶ ↑
模式匹配¶ ↑
-
模式匹配作为一项实验性功能引入。[功能 #14912]
case [0, [1, 2, 3]] in [a, [b, *c]] p a #=> 0 p b #=> 1 p c #=> [2, 3] end case {a: 0, b: 1} in {a: 0, x: 1} :unreachable in {a: 0, b: var} p var #=> 1 end case -1 in 0 then :unreachable in 1 then :unreachable end #=> NoMatchingPatternError json = <<END { "name": "Alice", "age": 30, "children": [{ "name": "Bob", "age": 2 }] } END JSON.parse(json, symbolize_names: true) in {name: "Alice", children: [{name: name, age: age}]} p name #=> "Bob" p age #=> 2 JSON.parse(json, symbolize_names: true) in {name: "Alice", children: [{name: "Charlie", age: age}]} #=> NoMatchingPatternError
-
有关更多详细信息,请参阅以下幻灯片
-
可以使用 -W:no-experimental 选项 抑制模式匹配警告。
关键字参数的规范已更改为 3.0¶ ↑
-
关键字参数和位置参数的自动转换已弃用,并且将在 Ruby 3 中删除转换。[功能 #14183]
-
当方法调用在最后一个参数处传递一个
Hash
,并且当它不传递任何关键字,并且当被调用的方法接受关键字时,会发出警告。要继续将哈希视为关键字,请添加双星号运算符以避免警告并确保在 Ruby 3 中的行为正确。def foo(key: 42); end; foo({key: 42}) # warned def foo(**kw); end; foo({key: 42}) # warned def foo(key: 42); end; foo(**{key: 42}) # OK def foo(**kw); end; foo(**{key: 42}) # OK
-
当方法调用将关键字传递给接受关键字的方法时,但它没有传递足够的必需位置参数,则关键字将被视为最终的必需位置参数,并会发出警告。将参数作为哈希而不是关键字传递以避免警告并确保在 Ruby 3 中的行为正确。
def foo(h, **kw); end; foo(key: 42) # warned def foo(h, key: 42); end; foo(key: 42) # warned def foo(h, **kw); end; foo({key: 42}) # OK def foo(h, key: 42); end; foo({key: 42}) # OK
-
当方法接受特定关键字但不接受关键字星号运算符时,并且传递给方法的哈希或关键字星号运算符包含
Symbol
和非 Symbol 键,则哈希将继续被拆分,并且会发出警告。您需要更新调用代码以传递单独的哈希以确保在 Ruby 3 中的行为正确。def foo(h={}, key: 42); end; foo("key" => 43, key: 42) # warned def foo(h={}, key: 42); end; foo({"key" => 43, key: 42}) # warned def foo(h={}, key: 42); end; foo({"key" => 43}, key: 42) # OK
-
如果方法不接受关键字,并且使用关键字调用,则关键字仍将被视为位置哈希,不会发出警告。此行为将在 Ruby 3 中继续有效。
def foo(opt={}); end; foo( key: 42 ) # OK
-
-
如果方法接受任意关键字,则非符号可以作为关键字参数键。[功能 #14183]
-
关键字参数哈希中的非 Symbol 键在 2.6.0 中被禁止,但现在再次允许。[错误 #15658]
def foo(**kw); p kw; end; foo("str" => 1) #=> {"str"=>1}
-
-
**nil
在方法定义中允许,以明确标记该方法不接受任何关键字。使用关键字调用此类方法将导致ArgumentError
。[功能 #14183]def foo(h, **nil); end; foo(key: 1) # ArgumentError def foo(h, **nil); end; foo(**{key: 1}) # ArgumentError def foo(h, **nil); end; foo("str" => 1) # ArgumentError def foo(h, **nil); end; foo({key: 1}) # OK def foo(h, **nil); end; foo({"str" => 1}) # OK
-
将空关键字星号运算符传递给不接受关键字的方法不再传递空哈希,除非空哈希对于必需参数是必要的,在这种情况下会发出警告。删除双星号运算符以继续传递位置哈希。[功能 #14183]
h = {}; def foo(*a) a end; foo(**h) # [] h = {}; def foo(a) a end; foo(**h) # {} and warning h = {}; def foo(*a) a end; foo(h) # [{}] h = {}; def foo(a) a end; foo(h) # {}
-
也可以使用 -W:no-deprecated 选项 抑制上述警告。
编号参数¶ ↑
-
引入了编号参数作为默认块参数。[特性 #4475]
[1, 2, 10].map { _1.to_s(16) } #=> ["1", "2", "a"] [[1, 2], [3, 4]].map { _1 + _2 } #=> [3, 7]
您仍然可以定义名为
_1
等的局部变量,并且在存在时会得到尊重,但会显示警告。_1 = 0 #=> warning: `_1' is reserved for numbered parameter; consider another name [1].each { p _1 } # prints 0 instead of 1
没有块的 proc/lambda 已被弃用¶ ↑
-
在使用块调用的方法中,没有块的
Proc.new
和Kernel#proc
现在将显示警告。def foo proc end foo { puts "Hello" } #=> warning: Capturing the given block using Kernel#proc is deprecated; use `&block` instead
可以使用-W:no-deprecated 选项来抑制此警告。
-
在使用块调用的方法中,没有块的
Kernel#lambda
会引发异常。def bar lambda end bar { puts "Hello" } #=> tried to create Proc object without a block (ArgumentError)
其他杂项更改¶ ↑
-
实验性地引入了无起始范围。它可能在
case
、Comparable#clamp
的新调用序列、常量和 DSL 中有用。[特性 #14799]ary[..3] # identical to ary[0..3] case RUBY_VERSION when ..."2.4" then puts "EOL" # ... end age.clamp(..100) where(sales: ..100)
-
将
$;
设置为非空值现在将显示警告。[特性 #14240] 这包括在String#split
中的使用。可以使用-W:no-deprecated 选项来抑制此警告。 -
将
$,
设置为非空值现在将显示警告。[特性 #14240] 这包括在Array#join
中的使用。可以使用-W:no-deprecated 选项来抑制此警告。 -
引用的 here-document 标识符必须在同一行内结束。
<<"EOS " # This had been warned since 2.4; Now it raises a SyntaxError EOS
-
翻转-翻转语法弃用已恢复。[特性 #5400]
-
注释行现在可以放置在流畅的点之间。
foo # .bar .baz # => foo.baz
-
现在允许使用文字
self
作为接收者调用私有方法。[特性 #11297] [特性 #16123] -
修改器 rescue 现在对多重赋值和单一赋值的操作相同。[错误 #8279]
a, b = raise rescue [1, 2] # Previously parsed as: (a, b = raise) rescue [1, 2] # Now parsed as: a, b = (raise rescue [1, 2])
-
单例类语法中的
yield
现在将显示警告。此行为很快将被弃用。[特性 #15575]。def foo class << Object.new yield #=> warning: `yield' in class syntax will not be supported from Ruby 3.0. [Feature #15575] end end foo { p :ok }
可以使用-W:no-deprecated 选项来抑制此警告。
-
引入了
(...)
的参数转发。[特性 #16253]def foo(...) bar(...) end
foo
的所有参数都会转发给bar
,包括关键字参数和代码块参数。请注意,括号是必须的。bar ...
被解析为一个无限范围。 -
访问和设置
$SAFE
现在将始终显示警告。$SAFE
将在 Ruby 3.0 中成为一个普通的全局变量。[特性 #16131] -
Object#{taint,untaint,trust,untrust}
和 C-API 中的相关函数不再有任何效果(所有对象始终被视为未污染),并且现在将在详细模式下显示警告。此警告将在 Ruby 3.0 中即使在非详细模式下也会被禁用,并且这些方法和 C 函数将在 Ruby 3.2 中被移除。[特性 #16131] -
细化发生在
Object#method
和Module#instance_method
中。[特性 #15373]
命令行选项¶ ↑
Warning
选项¶ ↑
-W
选项已扩展为带有一个后续的 :
,用于管理分类警告。[特性 #16345] [特性 #16420]
-
要抑制弃用警告
$ ruby -e '$; = ""' -e:1: warning: `$;' is deprecated $ ruby -W:no-deprecated -e '$; = //'
-
它与
RUBYOPT
环境变量一起使用$ RUBYOPT=-W:no-deprecated ruby -e '$; = //'
-
要抑制实验性特性警告
$ ruby -e '0 in a' -e:1: warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby! $ ruby -W:no-experimental -e '0 in a'
-
要使用
RUBYOPT
抑制两者,请设置用空格分隔的值$ RUBYOPT='-W:no-deprecated -W:no-experimental' ruby -e '($; = "") in a'
核心类更新(仅突出显示的更新)¶ ↑
数组
- 新方法
-
添加了
Array#intersection
。[特性 #16155] -
添加了
Array#minmax
,其实现比Enumerable#minmax
更快。[错误 #15929]
-
可比较
- 修改后的方法
-
Comparable#clamp
现在接受Range
参数。[特性 #14784]-1.clamp(0..2) #=> 0 1.clamp(0..2) #=> 1 3.clamp(0..2) #=> 2 # With beginless and endless ranges: -1.clamp(0..) #=> 0 3.clamp(..2) #=> 2
-
复数
- 新方法
-
添加了
Complex#<=>
。因此0 <=> 0i
不会引发NoMethodError
。[错误 #15857]
-
目录
编码
- 新编码
-
添加了新的编码 CESU-8。[特性 #15931]
-
可枚举
- 新方法
-
添加了
Enumerable#filter_map
。[功能 #15323][1, 2, 3].filter_map {|x| x.odd? ? x.to_s : nil } #=> ["1", "3"]
-
添加了
Enumerable#tally
。[功能 #11076]["A", "B", "C", "B", "A"].tally #=> {"A"=>2, "B"=>2, "C"=>1}
-
枚举器
- 新方法
-
添加了
Enumerator.produce
,用于从任何自定义数据转换生成Enumerator
。[功能 #14781]require "date" dates = Enumerator.produce(Date.today, &:succ) #=> infinite sequence of dates dates.detect(&:tuesday?) #=> next Tuesday
-
添加了
Enumerator::Lazy#eager
,它从惰性枚举器生成非惰性枚举器。[功能 #15901]a = %w(foo bar baz) e = a.lazy.map {|x| x.upcase }.map {|x| x + "!" }.eager p e.class #=> Enumerator p e.map {|x| x + "?" } #=> ["FOO!?", "BAR!?", "BAZ!?"]
-
添加了
Enumerator::Yielder#to_proc
,以便 Yielder 对象可以直接作为块参数传递给另一个方法。[功能 #15618] -
添加了
Enumerator::Lazy#with_index
,使其成为惰性操作。之前,Enumerator::Lazy#with_index
未定义,因此它从Enumerator
中获取了默认实现,该实现不是惰性的。[错误 #7877]("a"..).lazy.with_index(1) { |it, index| puts "#{index}:#{it}" }.take(3).force # => 1:a # 2:b # 3:c
-
纤程
- 新方法
-
添加了
Fiber#raise
,其行为类似于Fiber#resume
,但在恢复的纤程上引发异常。[功能 #10344]
-
文件
- 新方法
-
添加了
File.absolute_path?
,用于以可移植的方式检查路径是否为绝对路径。[功能 #15868]File.absolute_path?("/foo") # => true (on *nix) File.absolute_path?("C:/foo") # => true (on Windows) File.absolute_path?("foo") # => false
-
- 修改后的方法
-
File.extname
现在在非 Windows 平台上为以点结尾的名称返回点字符串。[错误 #15267]File.extname("foo.") #=> "."
-
冻结错误
- 新方法
-
添加了
FrozenError#receiver
,用于返回尝试修改其上的冻结对象。要在 Ruby 代码中引发FrozenError
时设置此对象,FrozenError.new
接受一个:receiver
选项。[功能 #15751]
-
垃圾回收
- 新方法
-
添加了
GC.compact
方法,用于压缩堆。此函数压缩堆中的活动对象,以便可以使用更少的页面,并且堆可能更适合 CoW(写时复制)。[功能 #15626]有关算法和注意事项的详细信息,请参阅此处:bugs.ruby-lang.org/issues/15626
-
IO
- 新方法
-
添加了
IO#set_encoding_by_bom
,用于检查 BOM 并设置外部编码。[错误 #15210]
-
整数
- 修改后的方法
-
Integer#[]
现在支持范围操作。[功能 #8842]0b01001101[2, 4] #=> 0b0011 0b01001100[2..5] #=> 0b0011 0b01001100[2...6] #=> 0b0011 # ^^^^
-
方法
- 修改后的方法
-
Method#inspect
显示更多信息。[功能 #14145]
-
模块
- 新方法
-
添加了
Module#const_source_location
用于检索定义常量的源位置。[功能 #10771] -
添加了
Module#ruby2_keywords
用于将方法标记为通过常规参数 splat 传递关键字参数,这在以与旧版 Ruby 版本向后兼容的方式将所有参数委托给另一个方法时很有用。[Bug #16154]
-
- 修改后的方法
-
Module#autoload?
现在接受一个可选的inherit
参数,类似于Module#const_defined?
。[功能 #15777] -
Module#name
现在始终返回一个冻结的String
。对于给定的Module
,返回的String
始终相同。此更改为实验性。[功能 #16150]
-
NilClass
/TrueClass
/FalseClass
- 修改后的方法
-
NilClass#to_s
、TrueClass#to_s
和FalseClass#to_s
现在始终返回一个冻结的String
。对于这些值中的每一个,返回的String
始终相同。此更改为实验性。[功能 #16150]
-
ObjectSpace::WeakMap
- 修改后的方法
-
ObjectSpace::WeakMap#[]=
现在接受特殊对象作为键或值。[功能 #16035]
-
Proc
- 新方法
-
添加了
Proc#ruby2_keywords
用于将 proc 标记为通过常规参数 splat 传递关键字参数,这在以与旧版 Ruby 版本向后兼容的方式将所有参数委托给另一个方法或 proc 时很有用。[功能 #16404]
-
Range
- 新方法
-
添加了
Range#minmax
,其实现比Enumerable#minmax
更快。它返回的现在对应于Range#max
的最大值。[Bug #15807]
-
- 修改后的方法
-
Range#===
现在也对String
参数使用Range#cover?
(在 Ruby 2.6 中,它从Range#include?
更改为除字符串之外的所有类型)。[Bug #15449]
-
RubyVM
- 删除了方法
-
RubyVM.resolve_feature_path
已移至$LOAD_PATH.resolve_feature_path
。[功能 #15903] [功能 #15230]
-
字符串
- Unicode
-
将 Unicode 版本和 Emoji 版本从 11.0.0 更新到 12.0.0。[功能 #15321]
-
将 Unicode 版本更新到 12.1.0,添加对 U+32FF 方形年号令和的支持。[功能 #15195]
-
将 Unicode Emoji 版本更新到 12.1。[功能 #16272]
-
符号
- 新方法
-
添加了
Symbol#start_with?
和Symbol#end_with?
方法。[功能 #16348]
-
时间
- 新方法
-
添加了
Time#ceil
方法。[功能 #15772] -
添加了
Time#floor
方法。[功能 #15653]
-
- 修改后的方法
-
Time#inspect
与Time#to_s
分开,它显示时间的小数秒。[功能 #15958]
-
未绑定方法
- 新方法
-
添加了
UnboundMethod#bind_call
方法。[功能 #15955]umethod.bind_call(obj, ...)
在语义上等效于umethod.bind(obj).call(...)
。此习惯用法在一些库中用于调用被覆盖的方法。添加的方法执行相同的操作,但不会分配中间的Method
对象。class Foo def add_1(x) x + 1 end end class Bar < Foo def add_1(x) # override x + 2 end end obj = Bar.new p obj.add_1(1) #=> 3 p Foo.instance_method(:add_1).bind(obj).call(1) #=> 2 p Foo.instance_method(:add_1).bind_call(obj, 1) #=> 2
-
警告
- 新方法
-
添加了
Warning.[]
和Warning.[]=
来管理发出/抑制某些类别的警告。[功能 #16345] [功能 #16420]
-
- $LOAD_PATH
- 新方法
-
添加了
$LOAD_PATH.resolve_feature_path
。[功能 #15903] [功能 #15230]
-
标准库更新(仅突出显示的更新)¶ ↑
Bundler
-
升级到
Bundler
2.1.2。请参阅 github.com/bundler/bundler/releases/tag/v2.1.2
-
CGI
-
CGI.escapeHTML
当至少有一个转义字符时,速度提高了 2~5 倍。请参阅 github.com/ruby/ruby/pull/2226
-
CSV
-
升级到 3.1.2。请参阅 github.com/ruby/csv/blob/master/NEWS.md。
-
日期
-
Date.jisx0301
、Date#jisx0301
和Date.parse
支持新的日本年号。[功能 #15742]
-
委托者
-
Object#DelegateClass
接受一个块并在返回的类上下文中对其进行模块评估,类似于Class.new
和Struct.new
。
-
ERB
-
禁止对
ERB
实例进行序列化。
-
IRB
-
在
Binding#irb
源代码行、REPL 输入和一些核心类对象的检查输出中引入受 Pry gem 启发的语法高亮。 -
引入由
Reline
提供的多行编辑模式。 -
在完成时显示文档。
-
默认情况下启用自动缩进和保存/加载历史记录。
-
JSON
-
升级到 2.3.0。
-
- Net::FTP
-
添加 Net::FTP#features 来检查可用功能,以及 Net::FTP#option 来启用/禁用每个功能。[功能 #15964]
-
Net::HTTP
-
在
Net::HTTP#start
中添加ipaddr
可选参数以替换 TCP/IP 连接的地址。[功能 #5180]
-
- Net::IMAP
-
添加服务器名称指示 (SNI) 支持。[功能 #15594]
-
- open-uri
OptionParser
-
现在为未知选项显示“您是否想说?”。[功能 #16256]
test.rb
require "optparse" OptionParser.new do |opts| opts.on("-f", "--foo", "foo") {|v| } opts.on("-b", "--bar", "bar") {|v| } opts.on("-c", "--baz", "baz") {|v| } end.parse!
示例
$ ruby test.rb --baa Traceback (most recent call last): test.rb:7:in `<main>': invalid option: --baa (OptionParser::InvalidOption) Did you mean? baz bar
-
Pathname
-
Pathname.glob
现在将 3 个参数委托给Dir.glob
以接受base
关键字。[功能 #14405]
-
- Racc
-
从上游存储库合并 1.4.15 并添加了 racc 的 cli。
-
Reline
-
新的标准库,与 readline 标准库兼容,但完全用 Ruby 实现。它还提供多行编辑模式。
-
- REXML
-
升级到 3.2.3。请参阅 github.com/ruby/rexml/blob/master/NEWS.md。
-
- RSS
-
升级到 RSS 0.2.8。请参阅 github.com/ruby/rss/blob/master/NEWS.md。
-
- RubyGems
StringScanner
-
升级到 1.0.3。参见 github.com/ruby/strscan/blob/master/NEWS.md。
-
兼容性问题(不包括功能错误修复)¶ ↑
-
以下库不再是捆绑的 gem。安装相应的 gem 以使用这些功能。
-
CMath (cmath gem)
-
Scanf (scanf gem)
-
Shell (shell gem)
-
Synchronizer (sync gem)
-
ThreadsWait (thwait gem)
-
E2MM (e2mmap gem)
-
Proc
-
The
Proc#to_s
格式已更改。[功能 #16101]
-
Range
-
Range#minmax
以前会遍历范围以确定最大值。现在它使用与Range#max
相同的算法。在极少数情况下(例如,浮点数或字符串的范围),这可能会产生不同的结果。[错误 #15807]
-
标准库兼容性问题(不包括功能错误修复)¶ ↑
-
将标准库提升为默认 gem
-
以下默认 gem 已发布在 rubygems.org 上
-
benchmark
-
cgi
-
delegate
-
getoptlong
-
net-pop
-
net-smtp
-
open3
-
pstore
-
readline
-
readline-ext
-
singleton
-
-
以下默认 gem 仅在 ruby-core 中提升,但尚未发布在 rubygems.org 上。
-
monitor
-
observer
-
timeout
-
tracer
-
uri
-
yaml
-
-
-
did_you_mean
gem 已从捆绑 gem 提升为默认 gem
- pathname
-
Kernel#Pathname
当使用Pathname
参数调用时,现在返回参数而不是创建新的Pathname
。这更类似于其他Kernel
方法,但可能会破坏修改返回值并期望参数不被修改的代码。
-
- profile.rb, Profiler__
-
已从标准库中删除。自 Ruby 2.0.0 以来一直没有维护。
-
C API 更新¶ ↑
-
已添加许多
*_kw
函数来设置是否应将传递的最后一个参数视为关键字。您可能需要切换到这些函数以避免关键字参数分离警告,并确保在 Ruby 3 中的行为正确。 -
在 rb_scan_args 格式字符串中,
:
字符现在被视为关键字参数。如果传递位置哈希而不是关键字参数,将发出弃用警告。 -
使用
ANYARGS
的 C API 声明已更改为不再使用ANYARGS
。请参阅 github.com/ruby/ruby/pull/2404
实现改进¶ ↑
纤程
-
允许使用
--with-coroutine=
选择不同的协程实现,例如:$ ./configure --with-coroutine=ucontext $ ./configure --with-coroutine=copy
-
用协程池缓存替换以前的堆栈缓存。协程池在单个内存区域中分配许多堆栈。堆栈分配变为 O(log N),协程创建被摊销为 O(1)。在微基准测试中测量到大约 10 倍的性能提升。 github.com/ruby/ruby/pull/2224
-
文件
-
File.realpath
现在在许多平台上使用 realpath(3),这可以显著提高性能。[功能 #15797]
-
哈希
-
更改小型
Hash
对象的数据结构。[功能 #15602]
-
监视器
-
Monitor
类是用 C 扩展编写的。[功能 #16255]
-
线程
-
VM 堆栈内存分配现在与原生线程堆栈合并,提高了线程分配性能并减少了与分配相关的失败。在微基准测试中测量到大约 10 倍的性能提升。
-
- JIT
-
当优化假设失效时,JIT 代码被重新编译为优化程度较低的代码。
-
Method
内联在方法被视为纯方法时执行。此优化仍处于实验阶段,许多方法尚未被视为纯方法。 -
--jit-max-cache
的默认值已从 1,000 更改为 100。 -
--jit-min-calls
的默认值已从 5 更改为 10,000。
-
RubyVM
-
自 1.9 左右开始存在的每个调用站点方法缓存已得到改进:缓存命中率从 89% 提高到 94%。请参阅 github.com/ruby/ruby/pull/2583
-
RubyVM::InstructionSequence
-
RubyVM::InstructionSequence#to_binary
方法生成编译后的二进制文件。二进制文件大小已减小。[功能 #16163]
-
其他更改¶ ↑
-
已删除对 IA64 架构的支持。测试硬件难以找到,原生协程代码难以实现,并且它给解释器增加了非平凡的复杂性。[功能 #15894]
-
要求编译器支持 C99。[杂项 #15347]
-
Ruby 的上游仓库已从 Subversion 迁移到 Git。
-
RUBY_DESCRIPTION 包含 Git 版本,而不是 Subversion 版本。
-
支持使用
_builtin
语法在 Ruby 中定义内置方法。[功能 #16254]一些方法在 *.rb 中定义(例如 trace_point.rb)。例如,定义一个接受关键字参数的方法很容易。