You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust循环创建结构体向量时触发E0382错误,求解决方案

解决Rust中"borrow of moved value"错误(Advent of Code 2022 Day1练习)

我正在学习Rust,通过Advent of Code 2022年第1天的题目练习。我打算创建一个包含Elf结构体的向量,每个Elf结构体里有一个calory_items向量。我尝试从文本文件解析数据,写了如下代码:

use std::io::{self, BufReader};
use std::path::Path;
use std::io::prelude::*;
use std::fs::File;

struct Elf {
    calory_items: Vec<i32>
}

fn parse_meal_list(source: &str) -> Vec<Elf> {
    let file = File::open(source).unwrap();
    let file = BufReader::new(file);
    
    let mut elves: Vec<Elf> = Vec::new();
    let mut elf = Elf {
        calory_items: Vec::new()
    };

    for line in file.lines() {
        let line = line.unwrap();
        if line.is_empty() {
            // create new Elf
            if elf.calory_items.len() > 0 {
                // in case there are two empty lines
                elves.push(elf);
                let mut elf: Elf = Elf { calory_items: Vec::new() };
            }
        } else {
            // append to current Elf object the calories
            let calory_item: i32 = line.parse().unwrap();
            elf.calory_items.push(calory_item)
        }
    }
    return elves;
}


fn main() {
    let input_day_1_source = Path::new("input_files/day_1.txt");
    let input_day_1_source = input_day_1_source.to_str().unwrap();
    let Elves: Vec<Elf> = parse_meal_list(input_day_1_source);
}

但编译器抛出如下错误:

error[E0382]: borrow of moved value: `elf`
  --> src/main.rs:23:16
   |
15 |     let mut elf = Elf {
   |         ------- move occurs because `elf` has type `Elf`, which does not implement the `Copy` trait
...
19 |     for line in file.lines() {
   |     ------------------------ inside of this loop
...
23 |             if elf.calory_items.len() > 0 {
   |                ^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
24 |                 // in case there are two empty lines
25 |                 elves.push(elf);
   |                            --- value moved here, in previous iteration of loop

我阅读了《Rust编程圣经》中关于借用检查器的内容,但仍不知道如何将元素添加到列表并归还所有权,或通过其他方式解决该问题。


错误原因

执行elves.push(elf)时,elf的所有权会被完全转移到向量elves中,原elf变量随即失效。而你在循环的下一次迭代中又试图访问这个已经失去所有权的变量,触发了借用检查器的错误。另外,你在if块内部重新声明的elf变量仅在块内有效,出了块之后外部的elf仍然处于无效状态。

修复方案

方案1:直接重置elf变量

在将elf推入向量后,直接给外部的elf变量赋值一个新的空Elf实例,不需要重新声明变量:

use std::io::{self, BufReader};
use std::path::Path;
use std::io::prelude::*;
use std::fs::File;

struct Elf {
    calory_items: Vec<i32>
}

fn parse_meal_list(source: &str) -> Vec<Elf> {
    let file = File::open(source).unwrap();
    let file = BufReader::new(file);
    
    let mut elves: Vec<Elf> = Vec::new();
    let mut elf = Elf {
        calory_items: Vec::new()
    };

    for line in file.lines() {
        let line = line.unwrap();
        if line.is_empty() {
            if !elf.calory_items.is_empty() {
                elves.push(elf);
                // 直接重置外部elf变量
                elf = Elf { calory_items: Vec::new() };
            }
        } else {
            let calory_item: i32 = line.parse().unwrap();
            elf.calory_items.push(calory_item)
        }
    }
    // 处理文件末尾没有空行结尾的最后一个Elf
    if !elf.calory_items.is_empty() {
        elves.push(elf);
    }
    elves
}


fn main() {
    let input_day_1_source = Path::new("input_files/day_1.txt");
    let input_day_1_source = input_day_1_source.to_str().unwrap();
    let elves: Vec<Elf> = parse_meal_list(input_day_1_source);
}

方案2:使用std::mem::replace

这个方法可以将当前elf的值替换为新的空实例,同时返回原来的elf值,再推入向量:

// 替换空行处理的代码块
if !elf.calory_items.is_empty() {
    let old_elf = std::mem::replace(&mut elf, Elf { calory_items: Vec::new() });
    elves.push(old_elf);
}

额外优化建议

  • 给Elf结构体添加计算总卡路里的方法,适配题目后续需求:
impl Elf {
    fn total_calories(&self) -> i32 {
        self.calory_items.iter().sum()
    }
}
  • 避免滥用unwrap(),可以让parse_meal_list返回Result<Vec<Elf>, io::Error>,优雅处理文件读取和解析错误。

内容的提问来源于stack exchange,提问作者Yorian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 13:18:10