I mentioned this earlier in the thread: Towards even smaller structs - #9 by comex
Stated more clearly, the expression foo.bar
, if bar
is a #[flat]
field, would copy bar
out of the object and produce an rvalue of whatever type it is. Then Rust's existing rules for taking references to rvalues would apply. This can be simulated in current Rust by adding braces – {foo.bar}
– which forces the expression to be an rvalue.
struct Foo { bar: i32 }
let foo = Foo { bar: 10 };
&{foo.bar};
^ OK, copies to the stack and takes a reference to that
std::ptr::addr_of!({foo.bar});
^ error[E0745]: cannot take address of a temporary
&mut {foo.bar};
^ Currently no error or warning, but probably should be an error when using flat fields without braces (heck, it should probably be a warning in all cases). It copies to the stack and only mutates the copy, not the original.
So the limitations are:
- The field type has to be
Copy
for this to make sense. - Since
&foo.bar
points to a stack copy, its lifetime is not the same as the lifetime offoo
. Any function like
fn get_bar(foo: &Foo) -> &i32 { &foo.bar }
will obviously not work.
- You can't usefully take a mutable reference. Though, I suppose the compiler could allow mutable references by making a stack copy, then automatically writing the modified value back to the original at the point the stack copy goes out of scope. But that would be going beyond "just make it an rvalue", it would require disabling NLL for those references, and I'm not sure if it's useful enough to justify the special case.
Still, it means that simple use cases, like calling &self
methods on #[flat]
fields, would 'just work'.