为什么可以从函数返回对文字的可变引用?

时间:2019-05-09 19:43:16

标签: 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)
    }
}

我对这行特别困惑:

let slice = mem::replace(&mut self.0, &mut []);
//                                    ^^^^^^^ 

此借入支票如何检查?如果这是不可变的借项,则RFC 1414表示[]右值应具有'static的生存期,以便不可变的借项将进行借阅检查,但该示例显示了可变的借项!看来必须进行以下两项操作之一:

  • []都是临时的(以便可以可变使用),在这种情况下,它将没有'static的生存期,并且不应借阅支票;
  • 或者[]的生存期为'static,因此,应该不可能进行可变借入(因为我们不能像借书时那样保证排他访问),也不应该借入-检查。

我想念什么?

相关:

1 个答案:

答案 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 []
}

另请参阅: