In Rust I have the following code:
pub trait Test: Sized {
const CONST: Self;
fn static_ref() -> &'static Self {
&Self::CONST
}
}
My expectation is that since const
is 'static
, then I should be able to take a reference to it that is also 'static
. However, the compiler gives the following error:
error[E0515]: cannot return reference to temporary value
--> file.rs:9:9
|
9 | &Self::CONST
| ^-----------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
How is a temporary variable being introduced here?
Additionally, it seems that there are some cases where taking a reference to a constant does work. Here is a short concrete example with a slightly different implementation of Test
pub trait Test: Sized {
fn static_ref() -> &'static Self;
}
struct X;
impl Test for X {
fn static_ref() -> &'static Self {
&X
}
}
A constant in Rust is a compile-time constant, not an actual variable with a memory location. The Rust compiler can substitute the actual value of the constant whereever it is used. If you take the address of such a value, you get the address of a temporary.
Rust also has the concept of a static variable. These variables actually have memory locations that are consistent for the whole program duration, and taking a reference to a static variable indeed results in a reference with 'static
lifetime.
See also:
When you define a trait, the definition must make sense for all possible implementations.
The problem may not be immediately clear without an example of where it fails. So suppose you had a type like this:
struct MyStruct;
impl MyStruct {
const fn new() -> Self {
MyStruct
}
}
And you attempted to implement the trait like this:
impl Test for MyStruct {
const CONST: Self = MyStruct::new();
}
This won't work because the implementation of static_ref
will now look like this:
fn static_ref() -> &'static Self {
// &Self::CONST
&MyStruct::new()
}
It's creating a value inside the function and trying to return it. This value is not static, so the 'static
lifetime is invalid.
However, with a little re-jigging, you can make something work:
pub trait Test: Sized + 'static {
// This is now a reference instead of a value:
const CONST: &'static Self;
fn static_ref() -> &'static Self {
Self::CONST
}
}
struct MyStruct;
impl MyStruct {
const fn new() -> Self {
MyStruct
}
}
impl Test for MyStruct {
const CONST: &'static Self = &MyStruct::new();
}
This works because CONST
is already a 'static
reference, so the function can just return it. All possible implementations would have to be able to obtain a 'static
reference to Self
to implement the trait, so there is no longer an issue with referencing some arbitrary local value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With