我发现了一个案例,其中手动内联函数会改变借用检查器处理它的方式,使其不再编译。据推测,它依赖于函数签名中的信息。如何在内联版本中提供此信息?
让'a
和'b
的有效期为'a
短于'b
(可以写成'b: 'a
)。
假设我有p: &'b mut f32
。我可以简要地借用p
(&mut p
)来获取q: &'a mut &'b mut f32
。
&'a mut &'b mut f32
等同于&'a mut &'a mut f32
,因为'b: 'a
?然后,我可以取消引用q
(使用*q
)来获取r: &'a mut f32
。我可以通过f32
(r
)写*r = something
,我可以稍后(生命期外'a
)通过p
读取值(带有*p
fn reborrow<'a, 'b: 'a>(q: &'a mut &'b mut f32) -> &'a mut f32 {
*q
}
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = reborrow(q);
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
)。
以下是一些我认为使用上述序列的工作代码:
*q
(在q
正文中用reborrow()
替换reborrow()
也有效,因为如果缺少必要的解引用,则会插入。
如果我手动内联fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = *q; <-- ERROR REPORTED HERE.
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
来电,则不再编译:
error[E0507]: cannot move out of borrowed content
let
谁带走了我的玩具?什么是类型推理思考/缺失?
我能否以某种方式注释r
绑定以使编译器推断出与之前版本相同的类型?
这是另一个有效的版本,但没有定义名称fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
**q = 2.718;
}
assert_eq!(*p, 2.718);
}
:
r
这是一个定义名称fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = &mut **q;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
并且有效的解决方法,但不使用相同的借用和解除引用序列:
$('.toggle-menu').click(function (e) {
e.preventDefault();
$('h4.toggle-menu').text($(this).text() == 'Menu' ? 'Close' : 'Menu');
$('.circle').toggleClass('Opacity');
$('#overlay-menu').delay(5000).toggleClass('Opacity');
$('.circle').toggleClass('open');
});
我制作了一个playground组合了所有四个版本。
答案 0 :(得分:7)
显而易见的解决方案可行,正如人们所期望的那样:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let r: &mut f32 = p;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
这似乎相对直观,是我期望新人最终得到的。
但是,如果你开始考虑它,那就没有意义了。如上所述,它看起来像:
let r: &mut f32 = p;
移动 out p
p
assert_eq!(*p, 2.718);
合理的解释是p
是Copy
,但它不是 1 !
答案是,隐含地,Rust正在幕后执行重新借用。也就是说,显式代码是:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let r: &mut f32 = &mut *p;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
我们可以通过在重新借用它之后尝试读取p
来检查这一点,并检查编译器错误:
error[E0502]: cannot borrow `p` as immutable because `*p` is also borrowed as mutable --> <anon>:6:24 | 5 | let r: &mut f32 = p; | - mutable borrow occurs here 6 | println!("{}", p); | ^ immutable borrow occurs here 7 | *r = 2.718; 8 | } | - mutable borrow ends here error: aborting due to previous error
这证实p
确实只是可变地借用,而不是移动,克隆或复制。
1 一个可变引用不能是Copy
甚至是Clone
,因为它会违反支持Rust安全的别名XOR Mutability原则。 < / p>
答案 1 :(得分:3)
我无法解释这一点,但你可以做一个与隐式取消引用相似的技巧,并说r
是&mut f32
:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r: &mut f32 = q;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}