函数参数中的可变借用 [英] Mutable borrow in function argument

查看:44
本文介绍了函数参数中的可变借用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么下面的代码不能编译(游乐场):

使用 std::collections::HashMap;fn 主(){让 mut h: HashMap= HashMap::new();h.插入(0, 0);h.insert(1, h.remove(&0).unwrap());}

借阅检查员抱怨:

error[E0499]: 不能一次多次借用 `h` 作为可变变量-->src/main.rs:6:17|6 |h.insert(1, h.remove(&0).unwrap());|- ------ ^ 第二个可变借用发生在这里|||||先借后调用|第一个可变借用发生在这里

然而,代码是安全的,最后一行几乎机械的转换使它编译(游乐场):

//h.insert(1, h.remove(&0).unwrap());让 x = h.remove(&0).unwrap();h.insert(1, x);

据我所知,这种问题可以通过非词法生命周期解决.这个问题 是一个例子,还有很多其他的.

毕竟有一些微妙之处使第一个变体不正确,所以 Rust 拒绝它是正确的吗?还是 NLL 功能还没有在所有情况下完成?

解决方案

你的问题也适用于一个可能更令人惊讶的相关案例——方法调用需要 &self 当方法参数需要 &mut self:

使用 std::collections::HashMap;fn 主(){让 mut h: HashMap= HashMap::new();h.插入(0, 0);h.contains_key(&h.remove(&0).unwrap());}

Rust 借用检查器使用它所谓的两阶段借用.我和 Niko Matsakis 的聊天:

<块引用>

两阶段借用的想法是,外部 &mut 被视为 & 借用,直到它被实际使用,或多或少.这使得它与内部 & 兼容,因为两个 & 混合,但它与内部 &mut 不兼容.>

如果我们想支持它,我们就必须添加一种新的借用方式——即未激活"的&mut 不会像 & 那样工作,它会像其他东西一样(&const,也许……"其他人可以变异")

不太清楚这是否可行,而且它似乎添加了更多概念,因此我们选择不支持它.

正如您所说,这是安全的,因为内部借用在外部借用开始之前完成,但实际上认识到此时在编译器中过于复杂.

另见:

Why doesn't the following code compile (playground):

use std::collections::HashMap;

fn main() {
    let mut h: HashMap<u32, u32> = HashMap::new();
    h.insert(0, 0);
    h.insert(1, h.remove(&0).unwrap());
}

The borrow checker complains that:

error[E0499]: cannot borrow `h` as mutable more than once at a time
 --> src/main.rs:6:17
  |
6 |     h.insert(1, h.remove(&0).unwrap());
  |     - ------    ^ second mutable borrow occurs here
  |     | |
  |     | first borrow later used by call
  |     first mutable borrow occurs here

The code is safe, however, and an almost mechanical transformation of the last line makes it compile (playground):

    //h.insert(1, h.remove(&0).unwrap());
    let x = h.remove(&0).unwrap();
    h.insert(1, x);

It was my understanding that this kind of issue got resolved with non-lexical lifetimes. This question is an example, and there are many others.

Is there some subtlety that makes the first variant incorrect after all, so Rust is correct to refuse it? Or is the NLL feature still not finished in all cases?

解决方案

Your question also applies for a related case that may be more surprising — having the method call require &self when the method argument requires &mut self:

use std::collections::HashMap;

fn main() {
    let mut h: HashMap<u32, u32> = HashMap::new();
    h.insert(0, 0);
    h.contains_key(&h.remove(&0).unwrap());
}

The Rust borrow checker uses what it calls two-phase borrows. An edited transcription of a chat I had with Niko Matsakis:

The idea of two-phase borrows is that the outer &mut is treated like an & borrow until it is actually used, more or less. This makes it compatible with an inner & because two & mix, but it is not compatible with an inner &mut.

If we wanted to support that, we'd have had to add a new kind of borrow -- i.e., an "unactivated" &mut wouldn't act like an &, it would act like something else (&const, maybe... "somebody else can mutate")

It's less clear that this is OK and it seemed to add more concepts so we opted not to support it.

As you stated, this is safe because the inner borrow is completed before the outer borrow starts, but actually recognizing that in the compiler is overly complex at this point in time.

See also:

这篇关于函数参数中的可变借用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆