简体   繁体   English

如何在不将其传递给函数的情况下重新导入可变引用?

[英]How can I reborrow a mutable reference without passing it to a function?

I have found a case where manually inlining a function changes the way the borrow-checker treats it, such that it no longer compiles. 我发现了一个案例,手动内联函数会改变借用检查器处理它的方式,使其不再编译。 Presumably it is relying on the information in the function signature. 据推测,它依赖于函数签名中的信息。 How can I provide this information in the inlined version? 如何在内联版本中提供此信息?

How I think it's working 我认为它是如何运作的

Let 'a and 'b be lifetimes with 'a shorter than 'b (which can be written 'b: 'a ). 'a'b生命周期为'a短于'b (可以写成'b: 'a )。

Suppose I have a p: &'b mut f32 . 假设我有一个p: &'b mut f32 I can borrow p briefly (with &mut p ) to obtain q: &'a mut &'b mut f32 . 我可以简单地借用p (用&mut p )来获得q: &'a mut &'b mut f32

  1. Have I correctly understood that &'a mut &'b mut f32 is equivalent to &'a mut &'a mut f32 because 'b: 'a ? 我是否正确地理解&'a mut &'b mut f32等同于&'a mut &'a mut f32因为'b: 'a

I can then dereference q (with *q ) to obtain r: &'a mut f32 . 然后我可以取消引用q (用*q )来获得r: &'a mut f32 I can write to the f32 via r (with *r = something ), and I can later (outside lifetime 'a ) read back the value via p (with *p ). 我可以通过r (带*r = something )写入f32 ,然后我可以在(生命周期外的'a )通过p (带*p )读回值。

With a function call 通过函数调用

Here is some working code that I think uses the above sequence: 以下是一些我认为使用上述顺序的工作代码:

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);
}

(Replacing *q with q in the body of reborrow() also works, because Rust inserts the necessary dereference if it is missing). (在reborrow()体中用q替换*q也有效,因为如果缺少必要的dereference,则会插入。

Manually inlined 手动内联

If I manually inline the reborrow() call, it no longer compiles: 如果我手动内联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
  1. Who took away my toys? 谁带走了我的玩具? What is the type inference thinking/missing? 什么是类型推断思考/缺失?

  2. Can I annotate the let binding somehow to make the compiler infer the same types as in the previous version? 我能否以某种方式注释let绑定以使编译器推断出与先前版本相同的类型?

Some other attempts 其他一些尝试

Here's another version that works, but which doesn't define the name r : 这是另一个有效的版本,但没有定义名称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);
}

Here's a work-around that defines the name r and works, but does not use the same sequence of borrows and dereferences: 这是一个定义名称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);
}

I made a playground combining all four versions. 我做了一个结合所有四个版本的游乐场

The obvious solution works, as one could expect: 人们可以预期,显而易见的解决方案有效:

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);
}

It seems relatively intuitive and is what I would expect a newcomer to end up with. 它似乎相对直观,是我期望新人最终得到的。


If you start thinking about it, however, it will not make sense. 但是,如果你开始考虑它,它将没有意义。 As described, it looks like: 如上所述,它看起来像:

  • let r: &mut f32 = p; moves out of p 移出 p
  • and yet we use p later in assert_eq!(*p, 2.718); 然而我们稍后在assert_eq!(*p, 2.718);使用p assert_eq!(*p, 2.718);

A reasonable explanation would be that p is Copy , however it's not 1 ! 一个合理的解释是pCopy ,但它不是1

The answer is that, implicitly, Rust is performing a re-borrowing behind the scenes. 答案是,Rust隐含地在幕后进行重新借用 That is, the explicit code is: 也就是说,显式代码是:

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);
}

We can check this by attempting to read p after re-borrowing it, and check the compiler error: 我们可以通过在重新借用后尝试读取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 

Which confirms that p is indeed only borrowed mutably, and not moved, cloned or copied. 这证实p确实只是可变地借用,而不是移动,克隆或复制。

1 A mutable reference cannot be Copy or even Clone as it would violate the Aliasing XOR Mutability principle which underpins Rust safety. 1 可变参考不能Copy甚至Clone因为它会违反支持Rust安全性的混叠XOR可变性原则。

I can't possibly begin to explain this, but you can do a similar trick as the implicit dereference and say that r is &mut f32 : 我不可能开始解释这一点,但你可以做一个与隐式解引用类似的技巧,并说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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在不递归的情况下删除此mandelbrot函数中的可变变量? - How can I remove the mutable variable in this mandelbrot function without recursion? 如何创建一次性可变引用? - how can I create a throwaway mutable reference? 给定一个可选的可变引用,我可以在不移动它的情况下将它传递给另一个 function 吗? - Given an optional mutable reference, can I pass it to another function without moving it? 如何在对结构的可变引用中交换字段的新值? - How can I swap in a new value for a field in a mutable reference to a structure? 如何通过 function 中的可变引用重新分配数组 - How do I reassign an array through a mutable reference in a function 如何使用 `index_mut` 来获取可变引用? - How can I use `index_mut` to get a mutable reference? 我怎样才能拥有一个采用可变引用的属性,该引用会比自身寿命更长? - How can I have a property that takes a mutable reference that will outlive itself? 如何更新 rust 循环中的可变引用? - How can I update a mutable reference in a rust loop? 将可变数组引用传递给也接受可变数组引用的函数时,为什么没有说明 &amp;mut? - When passing a mutable array reference into a function that also takes a mutable array reference, why is &mut not stated? 我可以使用可变的引用方法,例如值传递吗? - Can I use a mutable reference method like a value-passing one?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM