Ruby 4.0.0 發布
由 naruse 發表於 2025-12-25
翻譯: Bear Su
我們很高興宣布 Ruby 4.0.0 發布了。 Ruby 4.0 導入了 Ruby::Box 和 “ZJIT”,以及許多改進功能。
Ruby Box
Ruby Box 是一項用來提供定義區隔的(實驗性質)新功能。
可以透過設定環境變數 RUBY_BOX=1 啟用 Ruby Box。類別是 Ruby::Box。
在 Ruby Box 中載入的定義是互相隔離的。 Ruby Box 可以將從其他 boxes 載入的 monkey patches、全域/類別變數、類別/模組定義、和載入的原生/Ruby 函式庫做隔離。
預期的使用場景有:
- Run test cases in box to protect other tests when the test case uses monkey patches to override something
- 當測試案例使用 monkey patches 覆蓋時,在 box 環境中執行測試案例可以保護其他測試。
- 在 Ruby 進程中平行執行 Web 應用伺服器 boxes,以在應用程式伺服器上執行藍綠部署。
- 執行 Web 應用伺服器 boxes 來用 Ruby 程式碼檢查回應差異,評估特定時間段內的依賴更新。
- 作為基礎(底層)API,以實現某種「套件」(高層)API(尚未設計)。
參見 Ruby::Box 以了解更多關於「Ruby Box」的細節。 [Feature #21311] [Misc #21385]
ZJIT
ZJIT 是一個新型的即時 (JIT) 編譯器,它是作為 YJIT 的下一代產品而開發的。
要建置支援 ZJIT 的 Ruby,您需要 Rust 1.85.0 或更高版本,指定 --zjit 參數啟用 ZJIT。
我們之所以為 Ruby 建立一個新的編譯器,是因為我們既想提高效能上限(更大的編譯單元大小和 SSA IR),並鼓勵更多外部貢獻(透過成為一個更傳統的編譯器)。 參見 我們的部落格文章 來了解更多。
ZJIT 比直譯器快,但還不如 YJIT 快。 我們鼓勵您嘗試使用 ZJIT,但目前最好不要部署到生產環境中。 敬請期待 Ruby 4.1 的 ZJIT 版本。
Ractor 改進
Ruby 的平行執行機制 Ractor 已經得到了多項改進。
導入了一個新的類別 Ractor::Port,用於解決與訊息發送和接收相關的問題。 (參見 我們的部落格文章)。
此外,Ractor.shareable proc 讓在 Reactor 之間共用 Proc 物件變得更加容易。
在效能方面,許多內部資料結構都得到了改進,顯著減少了對全域鎖定的競爭,從而提高了平行執行的效率。 此外,Ractor 共用的內部資料也減少了,因此在平行執行時,CPU 快取競爭也相應降低。
Ractor 最初在 Ruby 3.0 中作為一項實驗性功能導入。我們計劃明年取消其「實驗性」狀態。
語法變更
-
*nil不再呼叫nil.to_a,就跟**nil不呼叫nil.to_hash一樣。[Feature #21047] -
位於行首的邏輯二元運算子(
||、&&、and和or)會延續前一行的內容,如同 fluent dot。 以下兩段程式碼是相同的效果:if condition1 && condition2 ... end之前:
if condition1 && condition2 ... endif condition1 && condition2 ... end
核心類別更新
注意:我們只列出特別的類別更新。
-
Array
- 新增
Array#rfind提供比array.reverse_each.find更有效率的替代方法。 [Feature #21678] - 新增
Array#find提供比Enumerable#find更有效率的 Override 方法。 [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。# 無限列舉 enum = Enumerator.produce(1, size: Float::INFINITY, &:succ) enum.size # => Float::INFINITY # 指定了已知/可計算大小的有限列舉 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。 最初的使用案例是當 IO 操作關閉時,用來中斷正在等待該阻塞 IO 操作的 fiber。 [Feature #21166] -
導入
Fiber::Scheduler#yield,允許 Fiber 調度器在訊號異常被停用時繼續處理。 [Bug #21633] -
重新導入
Fiber::Scheduler#io_closehook,用於非同步IO#close。 -
當刷新 IO 寫入緩衝區時呼叫
Fiber::Scheduler#io_write。 [Bug #21789]
-
-
File
File::Stat#birthtime現在可在核心與系統支援 statx 系統呼叫 的 Linux 上使用。 [Feature #21205]
-
IO
-
IO.select允許Float::INFINITY作為逾時參數。 [Feature #20610] -
移除被棄用的行為:透過
IO並在開頭使用|符號來建立行程 [Feature #19630]
-
-
Kernel
-
Kernel#inspect現在會檢查是否存在#instance_variables_to_inspect方法,這讓開發者可以控制哪些實體變數(instance variables)可以顯示在#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並在開頭使用|符號來建立 process。 [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(orRactor::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與Enumerator#to_set現在會進行大小檢查,以避免發生無窮範圍的問題。 [Bug #21654] -
Range#overlap?現在能正確處理無限(無邊界)範圍。 [Bug #21185] -
已修正
Range#max對於無開頭整數範圍的行為。 [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現在回傳適合用於eval的字串,並使用Set[]語法(例如:使用Set[1, 2, 3]而非#<Set: {1, 2, 3}>)。這讓它與 Array 和 Hash 等其他核心集合類別保持一致。 [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異常的可能,在這兩種情況下,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]
- 導入了
標準函式庫更新
我們只列出特別的標準函式庫更新。
若該項目在 GitHub 上有提供發布紀錄,我們也列出了從前一個隨附版本(即 Ruby 3.4.0)以來的發布歷史。
以下預設 gem 變更為隨附 gem:
- ostruct 0.6.3
- pstore 0.2.0
- 0.1.4 to v0.2.0
- benchmark 0.5.0
- logger 1.7.0
- rdoc 7.0.2
- win32ole 1.9.2
- 1.9.1 to 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 to v3.2.1
- english 0.8.1
- 0.8.0 to v0.8.1
- erb 6.0.1
- error_highlight 0.7.1
- etc 1.4.6
- fcntl 1.3.0
- 1.2.0 to v1.3.0
- fileutils 1.8.0
- 1.7.3 to v1.8.0
- forwardable 1.4.0
- 1.3.3 to v1.4.0
- io-console 0.8.2
- 0.8.1 to v0.8.2
- io-nonblock 0.3.2
- io-wait 0.4.0
- 0.3.2 to 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 to 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 to v0.4.2
- timeout 0.6.0
- uri 1.1.1
- weakref 0.1.4
- 0.1.3 to v0.1.4
- zlib 3.2.2
- 3.2.1 to v3.2.2
更新了以下隨附 gem。
- minitest 6.0.0
- power_assert 3.0.1
- rake 13.3.1
- test-unit 3.7.5
- rexml 3.4.4
- rss 0.3.2
- 0.3.1 to 0.3.2
- net-ftp 0.3.9
- 0.3.8 to v0.3.9
- net-imap 0.6.2
- net-smtp 0.5.1
- 0.5.0 to v0.5.1
- matrix 0.4.3
- 0.4.2 to v0.4.3
- prime 0.1.4
- 0.1.3 to v0.1.4
- rbs 3.10.0
- 3.8.0 to v3.8.1, v3.9.0.dev.1, v3.9.0.pre.1, v3.9.0.pre.2, v3.9.0, v3.9.1, v3.9.2, v3.9.3, v3.9.4, v3.9.5, v3.10.0.pre.1, v3.10.0.pre.2, v3.10.0
- typeprof 0.31.1
- debug 1.11.1
- 1.11.0 to v1.11.1
- base64 0.3.0
- 0.2.0 to v0.3.0
- bigdecimal 4.0.1
- drb 2.2.3
- 2.2.1 to v2.2.3
- syslog 0.3.0
- 0.2.0 to v0.3.0
- csv 3.3.5
- repl_type_completor 0.1.12
RubyGems and Bundler
Ruby 4.0 隨附 RubyGems 和 Bundler 4。詳情請參閱以下連結。
- Upgrading to RubyGems/Bundler 4 - RubyGems Blog
- 4.0.0 Released - RubyGems Blog
- 4.0.1 Released - RubyGems Blog
- 4.0.2 Released - RubyGems Blog
- 4.0.3 Released - RubyGems Blog
支援的平台
-
Windows
- 停止支援低於 14.0 (_MSC_VER 1900) 的 MSVC 版本。這意味著現在需要使用 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已被移除。 此函數曾用在已於 Ruby 2.7 移除的$SAFE路徑檢查,且此函數先前就已被棄用。 [Feature #20971] -
現在對於「參數數量錯誤」的
ArgumentError的 backtrace 會包含接收者的類別名稱或模組名稱(例如,在Foo#bar中,而不是在bar中)。 [Bug #21698] -
Backtraces 不再顯示「內部」幀。這些方法現在看起來像是在 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從標準函式庫移至核心類別,set/sorted_set.rb已被移除,且SortedSet不再是自動載入的常數。 若要使用SortedSet,請安裝sorted_setgem 並執行require 'sorted_set'。 [Feature #21287] -
Net::HTTP
- 對於帶有請求主體的請求(例如,
POST、PUT),已移除如果未明確設定標頭,預設自動將Content-Type標頭設為application/x-www-form-urlencoded的行為。 如果您的應用程式依賴此自動預設值,則您的要求現在將不帶 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 均可運作。這讓 gems 可以不必再檢查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 heaps 現在獨立增長,當只有部分集區包含長期存活的物件時,可以減少記憶體使用量。
- 在包含大量物件的分頁上 GC 掃描速度更快。
- 「Generic ivar」物件(String、Array、
TypedData等)現在使用新的內部「fields」對象,以加快實例變數的存取速度。 - GC 避免在首次使用之前維護內部的
id2ref表,從而加快了object_id的分配和 GC 掃描的速度。 object_id和hash在類別與模組物件上更快。- 較大的大數整數可以使用可變寬度分配來保持嵌入狀態。
Random、Enumerator::Product、Enumerator::Chain、Addrinfo,StringScanner、和一些內部物件現在也受到寫入屏障保護,這降低了 GC 的開銷。
Ractor
投入了大量心力來提升 Ractor 的穩定性、效能與易用性。這些改進使得 Ractor 的實作更接近脫離實驗性質的狀態。
- 效能提升
- 凍結字串與符號表在內部使用無鎖雜湊集合。 [Feature #21268]
- 方法快取查詢在多數情況下避免了鎖定。
- 類別(以及 eneric ivar)的實體變數存取速度更快,並避免了鎖定。
- 使用 per-ractor counter 在分配物件時避免 CPU 快取衝突。
- 使用 thread-local counter 在 in xmalloc/xfree 時避免 CPU 快取衝突。
object_id在多數情況下避免了鎖定。
- 修復錯誤與可靠性
- 修正了同時使用 Ractor 與 Thread 時可能發生的死鎖。
- 修正了在 Ractor 中使用 require 與 autoload 的問題。
- 修正了跨 Ractor 的編碼與轉碼問題。
- 修正了垃圾回收操作與方法失效時的競爭條件。
- 修正了啟動 Ractor 後,行程進行複製時的問題。
- 現在在 Ractors 下垃圾收集器的分配計數是準確的。
- 修正了垃圾回收後 TracePoints 無法正常工作的問題。 [Bug #19112]
JIT
- ZJIT
- 導入 基於實驗性方法的 JIT 編譯器。
如果可用,在執行時使用
--zjit選項或呼叫RubyVM::ZJIT.enable啟用 ZJIT,。 若要啟用--zjit支援,請使用 Rust 1.85.0 或更新版本來編譯 Ruby。 - 在 Ruby 4.0.0,ZJIT 的速度已超越直譯器,但尚未達到 YJIT 的水準。我們鼓勵大家嘗試 ZJIT,但目前建議不要將其部署於正式環境。
- 我們的目標是在 Ruby 4.1 中讓 ZJIT 的速度超越 YJIT,並達到可供正式環境使用的水準。
- 導入 基於實驗性方法的 JIT 編譯器。
如果可用,在執行時使用
- YJIT
RubyVM::YJIT.runtime_statsratio_in_yjit不再於預設建置中運作。 請使用--enable-yjit=stats在configure中啟用--yjit-stats。- 預設統計新增
invalidate_everything,當所有程式碼被 TracePoint 無效化時遞增。
RubyVM::YJIT.enable新增mem_size:和call_threshold:選項。
- RJIT
- 移除
--rjit。我們將把第三方 JIT API 的實作移至 ruby/rjit 儲存庫。
- 移除
參見 NEWS 和 commit logs 來了解更多。
自 Ruby 3.4.0 以來,計 3889 檔案變更,230769 行新增(+),297003 行刪減(-)。
耶誕快樂、佳節愉快,享受與 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 年開發的開源軟體。可以在許多平台上執行。使用者來自世界各地,特別活躍於網路開發領域。
最新消息
Ruby 4.0.1 發布
Ruby 4.0.1 已經發布了。
由 k0kubun 發表於 2026-01-13
Ruby 文件的新樣貌
繼重新設計 ruby-lang.org 之後,我們還有更多消息來慶祝 Ruby 誕生 30 週年: docs.ruby-lang.org 採用了 Aliki—RDoc’s 的全新預設主題。
由 Stan Lo 發表於 2025-12-23
重新設計我們的網站形象
我們很興奮地宣布網站進行了全面改版。這次更新的設計方案是由 Taeko Akatsuka 負責創作。
由 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