Reputation: 2280
I have a reference to a value and I would like to replace it with a reference to a wrapper struct wrapping the value.
Example:
struct Wrapper<T>(T);
let num = 123;
let x: &i32 = #
let wrapped: &Wrapper<i32> = .. // some conversion
Is this possible? (a safe solution is preferred, but not necessary.)
Upvotes: 2
Views: 144
Reputation: 88576
It's easy to make your example code work:
let wrapped: &Wrapper<i32> = &Wrapper(*x); // type annotation optional
Coming from C++, you might think this is crazily unsafe, because we take a reference to a temporary (the expression on the left hand side). But in situations like this, Rust just saves the result of this temporary expression on the stack. The above code is equivalent to:
let hidden = Wrapper(*x);
let wrapped: &Wrapper = &hidden;
So far so good, but a problem arises when we want to return this reference. For example:
fn wrap<T>(t: &T) -> &Wrapped<T> {
&Wrapped(*t)
}
We have two problems here. First, we can't move out of t
(it's only borrowed; it only worked in the code above because i32
is Copy
) and second, we can't return a reference to a local variable (the hidden
one that is created for us).
To solve this, you could use the unsafe
function std::mem::transmute()
. This just interprets any type as another any other type.
But wait! unsafe {}
means "compiler, trust me on this!", but should we trust ourselves? We as a programmer would have to guarantee that Wrapped<T>
and T
have the exact same data layout. So: is that the case?
It's probably true on most platforms, but I very much doubt we can guarantee this! Rust doesn't seem to promise a lot when it comes to data layout of structs (and unit structs). It may reorder fields (not important in this case) and may add padding. There is more information on this in the repr(Rust) chapter of the Rustonomicon.
To summarize: a function like wrap()
can't be safely implemented. As a consequence, APIs containing functions like that should be avoided.
Upvotes: 2
Reputation: 22173
You don't need any conversions; you can achieve this in the following manner:
#[derive(Debug)]
struct Wrapper(i32);
let num = 123; // the value
let x = # // the reference to the value
let wrapped: Wrapper = Wrapper(*x); // now you can refer to &wrapped
println!("{:?}", wrapped);
Upvotes: 1