为什么可以从函数返回对文字的可变引用? [英] Why is it possible to return a mutable reference to a literal from a function?
问题描述
The Rustonomicon 有这个示例代码:
The current edition of The Rustonomicon has this example code:
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)
}
}
我特别对这条线感到困惑:
I'm confused about this line in particular:
let slice = mem::replace(&mut self.0, &mut []);
// ^^^^^^^
这个借阅如何检查?如果这是一个不可变的借用,RFC 1414 表示 []
右值应该有 'static
生命周期,这样一个不可变借用会借用检查,但这个例子显示了一个可变借用!似乎必须发生两件事之一:
How does this borrow check? If this were an immutable borrow, RFC 1414 indicates that the []
rvalue should have 'static
lifetime, so that an immutable borrow would borrow-check, but the example shows a mutable borrow! It seems that one of two things must be going on:
- 要么
[]
是临时的(以便它可以可变地使用),在这种情况下它没有'static
生命周期,并且不应该借用检查; - 或者
[]
具有'static
生命周期,因此它不应该可以进行可变借用(因为我们不保证独占访问)借用),不应借用检查.
- Either
[]
is a temporary (so that it can be used mutably), in which case it would not have'static
lifetime, and should not borrow-check; - Or that
[]
has'static
lifetime, and therefore it should not be possible to take a mutable borrow (since we don't guarantee exclusive access as we take the borrow), and should not borrow-check.
我错过了什么?
相关:
这个问题关注的是不可变引用;这个问题是关于可变引用的.
This question focuses on immutable references; this question is about mutable references.
这个问题的重点是在函数内部获取引用;这个问题是关于返回一个参考.
This question focuses on taking references inside of a function; this question is about returning a reference.
推荐答案
TL;DR:空数组在编译器中是特殊情况,它是安全的,因为你永远不能解引用零长度数组的指针,所以有没有可能的可变别名.
TL;DR: empty arrays are special cased in the compiler and it's safe because you can't ever dereference the pointer of a zero-length array, so there's no possible mutable aliasing.
RFC 1414,右值静态提升,讨论了其机制值被提升为 static
值.它有一个关于可变引用(加粗我的):
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 (bolding mine):
可以扩展对 &'static mut
引用的支持,只要有额外的约束引用类型的大小为零.
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.
这再次在数组引用构造函数中具有优先权:
// valid code today
let y: &'static mut [u8] = &mut [];
规则类似:
- 如果采用对 constexpr 右值的可变引用.(
&mut
) - 并且 constexpr 不包含
UnsafeCell { ... }
构造函数. - 并且 constexpr 不包含返回包含
UnsafeCell
的类型的 const fn 调用. - 右值的类型为零.
- 然后不是将值转换到堆栈槽中,而是转换将它放入一个静态内存位置,并给结果引用一个
'static
生命周期.
- 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.
零尺寸限制是因为别名可变引用仅对零大小类型安全(因为您从不为它们取消引用指针).
由此,我们可以看出对空数组的可变引用目前在编译器中是特殊情况.在 Rust 1.39 中,讨论的扩展没有被实现:
From this, we can tell that mutable references to empty arrays are currently special-cased in the compiler. In Rust 1.39, the discussed extension has not been implemented:
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
虽然阵列版本确实有效:
While the array version does work:
fn example() -> &'static mut [i32] {
&mut []
}
另见:
这篇关于为什么可以从函数返回对文字的可变引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!