use std::mem;
use std::num::NonZero;
fn main() {
let a: Option<NonZero<u32>> = NonZero::<u32>::new(1);
let b: Option<Option<NonZero<u32>>> = Some(NonZero::<u32>::new(1));
let c: Option<Option<Option<NonZero<u32>>>> = Some(Some(NonZero::<u32>::new(1)));
let d: Option<Option<Option<Option<NonZero<u32>>>>> = Some(Some(Some(NonZero::<u32>::new(1))));
println!("{}", mem::size_of_val(&a)); // 4 (Bytes)
println!("{}", mem::size_of_val(&b)); // 8 (Bytes)
println!("{}", mem::size_of_val(&c)); // 8 (Bytes)
println!("{}", mem::size_of_val(&d)); // 8 (Bytes)
}
I wonder why b requires double the size in memory as a. Wouldn't it be ok to just refer to the most inner discriminant instead of requiring 4 more bytes for another discriminant?
NonZero gives enough room for None by repurposing the 0 value, but if you wrap another Option around it, where else is there to put another None? So expanding the type to use more space is only natural.
Ahhh you're right. When playing around I had for some reason the idea that the most inner discriminant could represent here "all Nones" which is of course wrong.
Thank you for your quick answers and explainations!
Start from a smaller type and you'll see more layers of Option are possible without the value getting bigger. For example, try Option<Option<Option<Option<Option<Option<bool>>>>>>.