Aid*_*lly 7 rust borrow-checker
当前版本的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)
}
}
Run Code Online (Sandbox Code Playgroud)
我特别对这条线感到困惑:
let slice = mem::replace(&mut self.0, &mut []);
// ^^^^^^^
Run Code Online (Sandbox Code Playgroud)
这个借书怎么查?如果这是一个不可变的借用,RFC 1414指出[]右值应该有'static生命周期,这样一个不可变的借用会借用检查,但这个例子显示了一个可变的借用!似乎必须发生两件事之一:
[]是临时的(以便它可以可变地使用),在这种情况下它没有'static生命周期,并且不应该借用检查;[]有'static生命周期,因此不应该进行可变借用(因为我们在借用时不保证独占访问),并且不应该借用检查。我错过了什么?
有关的:
这个问题侧重于不可变引用;这个问题是关于可变引用的。
这个问题的重点是在函数内部获取引用;这个问题是关于返回一个参考。
TL;DR:空数组在编译器中是特殊情况,它是安全的,因为您永远不能取消对零长度数组的指针的引用,因此没有可能的可变别名。
RFC 1414,右值静态提升,讨论了将值提升为static值的机制。它有一个关于可变引用的可能扩展的部分(我的粗体):
&'static mut只要存在引用类型为零大小的附加约束,就可以扩展对引用的支持。这在数组引用构造函数中再次具有优先级:
Run Code Online (Sandbox Code Playgroud)// valid code today let y: &'static mut [u8] = &mut [];规则是类似的:
- 如果采用对 constexpr 右值的可变引用。(
&mut <constexpr>)- 而且 constexpr 不包含
UnsafeCell { ... }构造函数。- 并且 constexpr 不包含返回包含
UnsafeCell.- 并且右值的类型为零大小。
- 然后,不是将值转换为堆栈槽,而是将其转换为静态内存位置并为结果引用提供
'static生命周期。存在零大小限制是因为别名可变引用仅对零大小类型是安全的(因为您永远不会为它们取消引用指针)。
由此,我们可以看出对空数组的可变引用目前在编译器中是特殊情况。在锈1.39,所讨论的分机已没有得到落实:
struct Zero;
fn example() -> &'static mut Zero {
&mut Zero
}
Run Code Online (Sandbox Code Playgroud)
struct Zero;
fn example() -> &'static mut Zero {
&mut Zero
}
Run Code Online (Sandbox Code Playgroud)
虽然阵列版本确实有效:
fn example() -> &'static mut [i32] {
&mut []
}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
| 归档时间: |
|
| 查看次数: |
648 次 |
| 最近记录: |