为什么对 const return 的静态引用是对临时变量的引用?
Why does taking a static reference to a const return a reference to a temporary variable?
在 Rust 中,我有以下代码:
pub trait Test: Sized {
const CONST: Self;
fn static_ref() -> &'static Self {
&Self::CONST
}
}
我的期望是,既然const
是'static
,那么我应该可以引用它也是'static
。但是,编译器给出以下错误:
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
这里怎么引入临时变量?
此外,似乎在某些情况下引用常量确实有效。这是一个简短的具体示例,其中 Test
的实现略有不同
pub trait Test: Sized {
fn static_ref() -> &'static Self;
}
struct X;
impl Test for X {
fn static_ref() -> &'static Self {
&X
}
}
Rust 中的一个 constant 是编译时常量,而不是具有内存位置的实际变量。 Rust 编译器可以在任何地方使用常量的实际 value 进行替换。如果你取这样一个值的地址,你得到的是一个临时的地址。
Rust 也有静态变量 的概念。这些变量实际上具有在整个程序持续时间内一致的内存位置,并且引用静态变量确实会导致引用具有 'static
生命周期。
另请参阅:
定义特征时,该定义必须对所有可能的实现都有意义。
如果没有失败的示例,问题可能不会立即清楚。所以假设你有这样的类型:
struct MyStruct;
impl MyStruct {
const fn new() -> Self {
MyStruct
}
}
并且您试图实现这样的特征:
impl Test for MyStruct {
const CONST: Self = MyStruct::new();
}
这行不通,因为 static_ref
的实施现在看起来像这样:
fn static_ref() -> &'static Self {
// &Self::CONST
&MyStruct::new()
}
它正在函数内部创建一个值并尝试 return 它。此值 不是 静态的,因此 'static
生命周期无效。
但是,稍加调整,您就可以做出一些工作:
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();
}
这是可行的,因为 CONST
已经是一个 'static
引用,所以函数可以 return 它。所有可能的实现都必须能够获得对 Self
的 'static
引用才能实现该特征,因此引用某个任意本地值不再有问题。
这里的工作机制是静态提升。
参见 RFC 1414
引述如下:
Inside a function body's block:
- If a shared reference to a constexpr rvalue is taken. (&)
- And the constexpr does not contain a UnsafeCell { ... } constructor.
- And the constexpr does not contain a const fn call returning a type
containing a UnsafeCell.
- Then instead of translating the value into a
stack slot, translate it into a static memory location and give the
resulting reference a 'static lifetime.
在 Rust 中,我有以下代码:
pub trait Test: Sized {
const CONST: Self;
fn static_ref() -> &'static Self {
&Self::CONST
}
}
我的期望是,既然const
是'static
,那么我应该可以引用它也是'static
。但是,编译器给出以下错误:
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
这里怎么引入临时变量?
此外,似乎在某些情况下引用常量确实有效。这是一个简短的具体示例,其中 Test
的实现略有不同pub trait Test: Sized {
fn static_ref() -> &'static Self;
}
struct X;
impl Test for X {
fn static_ref() -> &'static Self {
&X
}
}
Rust 中的一个 constant 是编译时常量,而不是具有内存位置的实际变量。 Rust 编译器可以在任何地方使用常量的实际 value 进行替换。如果你取这样一个值的地址,你得到的是一个临时的地址。
Rust 也有静态变量 的概念。这些变量实际上具有在整个程序持续时间内一致的内存位置,并且引用静态变量确实会导致引用具有 'static
生命周期。
另请参阅:
定义特征时,该定义必须对所有可能的实现都有意义。
如果没有失败的示例,问题可能不会立即清楚。所以假设你有这样的类型:
struct MyStruct;
impl MyStruct {
const fn new() -> Self {
MyStruct
}
}
并且您试图实现这样的特征:
impl Test for MyStruct {
const CONST: Self = MyStruct::new();
}
这行不通,因为 static_ref
的实施现在看起来像这样:
fn static_ref() -> &'static Self {
// &Self::CONST
&MyStruct::new()
}
它正在函数内部创建一个值并尝试 return 它。此值 不是 静态的,因此 'static
生命周期无效。
但是,稍加调整,您就可以做出一些工作:
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();
}
这是可行的,因为 CONST
已经是一个 'static
引用,所以函数可以 return 它。所有可能的实现都必须能够获得对 Self
的 'static
引用才能实现该特征,因此引用某个任意本地值不再有问题。
这里的工作机制是静态提升。 参见 RFC 1414
引述如下:
Inside a function body's block:
- If a shared reference to a constexpr rvalue is taken. (&)
- And the constexpr does not contain a UnsafeCell { ... } constructor.
- And the constexpr does not contain a const fn call returning a type containing a UnsafeCell.
- Then instead of translating the value into a stack slot, translate it into a static memory location and give the resulting reference a 'static lifetime.