如何在 if-let 语句中将复制的变量引入为可变变量?

问题描述 投票:0回答:2

我有一个

HashMap<i8, i8>
,它可以包含循环:

let mut x: HashMap<i8, i8> = HashMap::new();
x.insert(1, 6);
x.insert(3, 5);
x.insert(5, 1);

要获取

3
的最终值,应首先查找
x[3]
,然后查找
x[5]
,最后查找
x[1]
,这应该会产生
6
。我决定使用
while let
循环:

let mut y = x[&3]; // y: i8
while let Some(&z) = x.get(&y) {
    y = z;
}

println!("{}", y);

x.insert(0, 0);

这工作正常,但如果

panic!
不在地图中,则会
3
。由于我不想对
None
的情况做任何事情,所以我想使用
if let
(类似于使用的
while let
)。

我尝试了一些符号:

  1. if let Some(&y) = x.get(&3)
    :复制值,但 y 是不可变的 (
    y: i8
    )
  2. if let Some(mut y) = x.get(&3)
    :y 是可变的,但值是借用的 (
    mut y: &i8
    )
  3. if let mut Some(&y) = x.get(&3)
    :我的目标:可变副本,但语法无效(
    mut y: i8

(所有变体都可以在 Rust Playground 获得,但您需要注释掉第三次尝试,因为它是无效语法)

我不会争论第二种变体,但我需要将值插入到

if let
正文中的地图中。由于地图仍然是借来的,我无法再插入。我所需要的只是复制
Some(y)
中的值,并且
y
是可变的,以便借用检查器满意,我可以进行递归查找。

rust mutable
2个回答
7
投票

你的方法 #1 是完全正确的匹配,你只需要使

y
变量可变即可。一种可能性是将
Option<&i8>
转换为
Option<i8>
,从而能够在图案中使用
mut y
。例如,
Option::map
可以取消引用该值:

if let Some(mut y) = x.get(&3).map(|ref| *ref) {

由于

Copy
意味着(便宜)
Clone
,您可以使用
Option::cloned()
:

来表达相同的意思
if let Some(mut y) = x.get(&3).cloned() {

从 Rust 1.35 开始,您可以使用

Option::copied()
,它保证只复制值(如果值不是
Copy
,则无法编译):

if let Some(mut y) = x.get(&3).copied() {

另一种可能性是保持你的方法 #1 不变,但只需在

if let
块内引入一个单独的可变变量即可纠正它:

if let Some(&y) = x.get(&3) {
    let mut y = y;
    ...

2
投票

你的代码基本上可以工作:

use std::collections::HashMap;

fn main() {
    let mut x: HashMap<i8, i8> = HashMap::new();
    x.insert(1, 6);
    x.insert(3, 5);
    x.insert(5, 1);

    let mut key = 3;
    while let Some(&z) = x.get(&key) {
        key = z;
    }

    println!("{}", key);

    x.insert(key, 0);
}

这里,

key
被保留为最后一个不匹配的键。

© www.soinside.com 2019 - 2024. All rights reserved.