Ruby 中的 Struct 是什麼?
Struct 是 Ruby 內建類別,用來建立產生 value objects 的新類別。Value object 用於將相關屬性儲存一起。
舉個例子:
一個 Point 有兩個座標(x 和 y)。
你可以用多種方式表示這個資料。
像這樣:
- 陣列
[10, 20] - 雜湊
{ x: 10, y: 10 } - 物件
Point.new(10, 20)
如果你會有一個以上的 Point,用物件方法通常是個好習慣。
但是……
你不想只為了儲存這兩個值就建立一整個類別!
用 Struct 解決這個問題。
內容
- 1 如何在 Ruby 中建立 Structs
- 1.1 替代方式
- 1.2 最大好處
- 2 如何使用 Ruby Structs
- 3 警告:Structs 可能很棘手
- 3.1 另一件怪事
- 4 Ruby 2.5 的關鍵字參數
- 5 如何使用 OpenStruct
- 6 Struct vs OpenStruct
- 7 觀看影片教學
- 8 結論
- 8.1 相關
開始吧!
如何在 Ruby 中建立 Structs
你可以呼叫 new 並傳入一組 symbol 來建立 Struct,這些 symbol 會成為這個類別的 instance variables。
它們預設會定義 accessor methods,讀寫都有。
例子:
Person = Struct.new(:name, :age, :gender)
現在你可以這樣建立物件:
john = Person.new "john", 30, "M" david = Person.new "david", 25, "M"
替代方式
你可能在外面看到另一種建立 structs 的方式。
長這樣:
class Person < Struct.new(:name, :age, :gender) end
我不推薦這個。
但如果你在外面看到,現在你知道它幹嘛的了。
最大好處
Struct 的一個好處是你可以直接比較它們,基於它們的屬性。
例子:
john == john # true
如果這是一般 Ruby 物件,你得自己定義 == 方法。
這就是我們所謂的 "value object"。
如何使用 Ruby Structs
用 struct 比陣列或雜湊好處之一是你可以用方法存取 struct members。
例如:
puts john.age # 30 puts david.gender # "M"
這很有幫助,因為如果你有物件陣列,可以用 max, select, sum 等方法。
例子:
[john, david].max_by(&:age)
不錯!
警告:Structs 可能很棘手
Struct 產生的類別另一個注意點是……
它們 不會強制建構式的正確參數數量!
讓我解釋。
用一般類別你會看到這個錯誤:
ArgumentError: wrong number of arguments (0 for 3)
但用 Struct 缺少的參數會變成 nil:
Person.new("peter") # struct Person name="peter", age=nil, gender=nil 使用 Struct 物件時記住這點!
另一件怪事
看看這個……
Struct.new(:a).ancestors [#<Class:0x29b1040>, Struct, Enumerable, Object, Kernel, BasicObject]
這個 #<Class:0x29b1040> 是加在 structs 的匿名類別,也注意到 enumerable 模組,讓你能呼叫 each 和 map 等方法。
Ruby 2.5 的關鍵字參數
假設你從檔案讀取行,每行代表一個項目。
例子:
200 /login 18:00 404 /bacon 18:03 200 /books 18:04
如果建立自訂類別會更容易處理這資料。
像這樣:
LogEntry = Struct.new(:status, :url, :time) LogEntry.new(200, '/books', '18:04')
但為了讓每個參數代表什麼更清楚,你可能想用關鍵字參數。
好消息!
Ruby 2.5 加入了 Struct 物件的關鍵字參數支援。
用法:
LogEntry = Struct.new(:status, :url, :time, keyword_init: true) LogEntry.new(status: 200, url: '/books', time: '18:04')
現在你可以解析檔案並轉換成 LogEntry 物件!
如何使用 OpenStruct
如果你只需要一次性物件,應該考慮用 OpenStruct。
程式碼範例:
require 'ostruct' cat = OpenStruct.new(color: 'black') puts cat.class puts cat.color
注意你必須 require 'ostruct' 才能用這個類別。
警告:OpenStruct 很慢,根據 schneems 的 reddit 留言,不應在 production apps 使用。我也找到這篇部落格有基準測試支持這點。
Struct vs OpenStruct
Struct 和 OpenStruct 的差別:
- Struct 建立 新類別 帶有預定義屬性、等值方法 (==) 和 enumerable
- OpenStruct 建立 新物件 帶有給定屬性
OpenStruct 是花俏的 Hash 物件,而 Struct 像是從模板建立新類別。
觀看影片教學
結論
你學會了 Ruby Struct 和 OpenStruct!只要了解各自的特殊特性你就沒問題。

現在輪到你練習了 🙂