为什么可以 return 对函数文字的可变引用?

Why is it possible to return a mutable reference to a literal from a function?

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 生命周期,这样一个不可变借用将进行借用检查,但这个例子显示了一个可变借用!似乎必须进行以下两件事之一:

我错过了什么?

相关:

TL;DR: 空数组在编译器中是特殊情况,它是安全的,因为你永远不能取消引用零长度数组的指针,所以不可能有可变别名。


RFC 1414, rvalue static promotion, discusses the mechanism by which values are promoted to static values. It has a section about possible extensions for mutable references(加粗我的):

It would be possible to extend support to &'static mut references, as long as there is the additional constraint that the referenced type is zero sized.

This again has precedence in the array reference constructor:

// valid code today
let y: &'static mut [u8] = &mut [];

The rules would be similar:

  • If a mutable reference to a constexpr rvalue is taken. (&mut <constexpr>)
  • 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.
  • And the type of the rvalue is zero-sized.
  • 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.

The zero-sized restriction is there because aliasing mutable references are only safe for zero sized types (since you never dereference the pointer for them).

从这里我们可以看出,对空数组的可变引用目前在编译器中是特殊情况。在 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 []
}

另请参阅: