The Rustonomicon的当前版本具有以下示例代码:
use std::mem;
pub struct IterMut<'a, T: 'a>(&'a mut [T]);
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
let slice = mem::replace(&mut self.0, &mut []);
if slice.is_empty() {
return None;
}
let (l, r) = slice.split_at_mut(1);
self.0 = r;
l.get_mut(0)
}
}
我对这行特别困惑:
let slice = mem::replace(&mut self.0, &mut []);
// ^^^^^^^
此借入支票如何检查?如果这是不可变的借项,则RFC 1414表示[]
右值应具有'static
的生存期,以便不可变的借项将进行借阅检查,但该示例显示了可变的借项!看来必须进行以下两项操作之一:
[]
都是临时的(以便可以可变使用),在这种情况下,它将没有'static
的生存期,并且不应借阅支票; []
的生存期为'static
,因此,应该不可能进行可变借入(因为我们不能像借书时那样保证排他访问),也不应该借入-检查。我想念什么?
相关:
Why can I return a reference to a local literal but not a variable?
这个问题集中在不可变的引用上;这个问题是关于可变引用的。
Why is it legal to borrow a temporary?
这个问题的重点是在函数内部获取引用;这个问题是关于返回参考。
答案 0 :(得分:2)
TL; DR:空数组在编译器中是特殊情况,它是安全的,因为您永远都无法解除对零长度数组的指针的引用,因此不会发生可变的别名。
RFC 1414,右值静态提升,讨论了将值提升为static
值的机制。其中有一个有关mutable references的可能扩展名(与我联系)的部分:
可以将支持扩展到
&'static mut
个引用, 只要存在其他约束条件 引用的类型为零大小。这又在数组引用构造函数中具有优先权:
// valid code today let y: &'static mut [u8] = &mut [];
规则类似:
- 如果采用可变引用constexpr rvalue。 (
&mut <constexpr>
)- 并且constexpr不包含
UnsafeCell { ... }
构造函数。- 并且constexpr不包含const fn调用,该调用返回的类型包含
UnsafeCell
。- 并且右值的类型为零。
- 然后,不要将值转换为堆栈插槽,而是转换 将其放入静态内存位置,并给结果引用a
'static
一生。存在零位限制是因为 别名可变引用仅对零大小类型安全 (因为您从未取消引用它们的指针)。
由此,我们可以看出,对空数组的可变引用当前在编译器中为特殊情况。在Rust 1.39中,尚未实现所讨论的扩展名 :
struct Zero;
fn example() -> &'static mut Zero {
&mut Zero
}
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:4:5
|
4 | &mut Zero
| ^^^^^----
| | |
| | temporary value created here
| returns a reference to data owned by the current function
虽然阵列版本可以工作:
fn example() -> &'static mut [i32] {
&mut []
}
另请参阅: