首页 > 解决方案 > 重复更新和输出数据结构

问题描述

我有一个fruitlist: Vec<&mut Groceries>不易复制的可变数据结构 ( )。我想反复更新和输出它。这是一个最小的例子:

// Note that Groceries do not implement the Copy trait                                                                   
struct Groceries {
    amount: u32,
    item: String,
}

// takes mutable references because we will alter the Groceries                                                          
fn update_groceries(groceries: Vec<&mut Groceries>) {
    // Double everything we have, just in case of a pandemic                                                             
    for g in groceries {
        g.amount *= 2;
    }
}

// takes immutable references because we will only need to read them                                                     
fn output_groceries(groceries: Vec<&Groceries>) {
    for g in groceries {
        println!("{}: {}", g.item, g.amount);
    }
}

fn main() {
    // We start with a list of fruit                                                                                     
    let mut bananas: Groceries = Groceries{amount:3, item: String::from("yellow bananas")};
    let mut oranges: Groceries = Groceries{amount:2, item: String::from("oranges")};
    let fruitlist: Vec<&mut Groceries> = vec![
        &mut bananas,
        &mut oranges,
    ];

    // Now we want to update and print the list                                                                          

    update_groceries(fruitlist);
    // the following line is necessary to get from Vec<&mut Groceries> to Vec<& Groceries>                               
    let fruitlist_immutable_references: Vec<& Groceries> = fruitlist.into_iter().map(|x| &*x).collect();
    output_groceries(fruitlist_immutable_references);

    // This update and print part might happen multiple times in a loop.                                                 
}

这失败了,因为fruitlist正在移动:

error[E0382]: use of moved value: `fruitlist`
  --> src/main.rs:38:60
   |
29 |     let fruitlist: Vec<&mut Groceries> = vec![
   |         --------- move occurs because `fruitlist` has type `std::vec::Vec<&mut Groceries>`, which does not implement the `Copy` trait
...
36 |     update_groceries(fruitlist);
   |                      --------- value moved here
37 |     // the following line is necessary to get from Vec<&mut Groceries> to Vec<& Groceries>
38 |     let fruitlist_immutable_references: Vec<& Groceries> = fruitlist.into_iter().map(|x| &*x).collect();
   |                                                            ^^^^^^^^^ value used here after move

当我注释掉更新时,代码工作正常。

我发现自己一次又一次地以不同的形式遇到这个问题。我怎样才能使这种模式起作用?或者有没有更好的方法来重复更新和输出复杂的数据结构?

(线定义fruitlist_immutable_references也很丑。我希望有更好的方法)

标签: rustlifetimeborrow-checkerownershipborrowing

解决方案


如果您将列表按值(例如list: Vec<&mut Groceries>)传递给函数,那么它将列表的所有权转移到函数中。相反,您应该通过引用(例如list: &mut [&mut Groceries],或list: &[&Groceries])传递它以维护列表的所有权。固定示例:

// Note that Groceries do not implement the Copy trait                                                                   
struct Groceries {
    amount: u32,
    item: String,
}

// takes mutable references because we will alter the Groceries                                                          
fn update_groceries(groceries: &mut [&mut Groceries]) {
    // Double everything we have, just in case of a pandemic                                                             
    for g in groceries {
        g.amount *= 2;
    }
}

// takes immutable references because we will only need to read them                                                     
fn output_groceries(groceries: &[&Groceries]) {
    for g in groceries {
        println!("{}: {}", g.item, g.amount);
    }
}

fn main() {
    // We start with a list of fruit                                                                                     
    let mut bananas: Groceries = Groceries { amount:3, item: String::from("yellow bananas") };
    let mut oranges: Groceries = Groceries { amount:2, item: String::from("oranges") };
    let mut fruitlist: Vec<&mut Groceries> = vec![
        &mut bananas,
        &mut oranges,
    ];

    // Now we want to update and print the list                                                                          
    update_groceries(&mut fruitlist);
    
    // the following line is necessary to get from Vec<&mut Groceries> to Vec<& Groceries>                               
    let fruitlist_immutable_references: Vec<&Groceries> = fruitlist.into_iter().map(|x| &*x).collect();
    output_groceries(&fruitlist_immutable_references);

    // This update and print part might happen multiple times in a loop.                                                 
}

操场


推荐阅读