当你有Option<&T>
时,编译器知道NULL
永远不是&T
和encodes the None
variant as NULL
instead的可能值。这样可以节省空间:
use std::mem;
fn main() {
assert_eq!(mem::size_of::<&u8>(), mem::size_of::<Option<&u8>>());
}
但是,如果使用非指针类型执行相同的操作,则无需额外的位来存储该值,并且需要额外的空间:
use std::mem;
fn main() {
// fails because left is 1 and right is 2
assert_eq!(mem::size_of::<u8>(), mem::size_of::<Option<u8>>());
}
一般来说,这是正确的。但是,我想选择加入优化,因为我知道我的类型有某些不可能的值。作为一个例子,我可能有一个有年龄的玩家角色。年龄可能未知,但永远不会高于255
:
struct Age(u8);
struct Player {
age: Option<Age>,
}
我希望能够告知优化程序此约束 - Age
永远不会是255
,因此将该位模式用作{{1}是安全的}}。这可能吗?
答案 0 :(得分:19)
从Rust 1.28开始,您可以使用implode()
(和朋友)。这作为一个包装器,告诉编译器一个数字的内容将从不包含一个文字零。这也是Option<Box<T>>
指针大小的原因。
以下是一个示例,说明如何创建Age
并阅读其有效负载。
use std::num::NonZeroU8;
struct Age(NonZeroU8);
impl Age {
pub fn new(age: u8) -> Age {
let age = NonZeroU8::new(age).expect("Age cannot be zero!");
Age(age)
}
pub fn age(&self) -> u8 {
self.0.get()
}
}
struct Player {
age: Option<Age>,
}
fn main() {
println!("size: {}", std::mem::size_of::<Player>());
// Output: size: 1
}