Option 的大小
Wu Yu Wei published on
3 min,
471 words
在 Rust 中預設是不能使用 Null
指標/引用的,而當時的設計者 Tony Hoare 也說了這是造成數十億損失的錯誤設計。所以通常我們會使用 Option
型態來表示可能會有 Null
值的型態。這麼做帶來很多好處,所有型態預設都是沒有 Null
的,而 Option<T>
剛好也形成一種 monadic structure。你可以在不和原生型態衝突的狀況下,自己定義他的運算行爲。
但是對於資源吃緊的裝置來說,我們就會在意型態的大小了。我們很清楚的知道 u64
就是有 64 bits 所以會佔 8 bytes,但是 Option<u64>
的話就需要多一個 bit 來儲存 None
,所以一開始想的話我們應該會覺得它應該會佔 9 bytes,但結果卻是 16 bytes。
assert_eq!(9, std::mem::size_of::<Option<u64>>());
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `9`,
right: `16`', src/main.rs:2:5
這是因爲像是在 64-bit 的平台上的 CPU 都是 word-oriented,所有的形態預設都需要 align 爲 8 bytes 的界限。這樣就造成了一些效能的損失,當然這些在平常的應用開發不太重要,編譯器甚至能優化掉,但如果是要寫非常注重空間或記憶體消耗的話(像是寫 file system, kernel module 或 嵌入式系統),可能就需要一些考慮了。爲此 std::num
提供了沒有零的原生型態像是 NonZeroU8
, NonZeroUsize
等等。因爲他們的 0 是用不到的,所以作爲 Option
型態的話,就可以剛好給 None
使用。這樣一來大小絕對就和原本的型態一樣了。
assert_eq!(8, std::mem::size_of::<Option<std::num::NonZeroU64>>());