在 Rust 中调用循环中的函数时,无法一次借用可变多次错误

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

我正在尝试使用我在 Rust 中创建的函数来提出一系列选择,供用户从中进行选择,然后从该选择中执行关联的函数。但是,当我在循环中使用它时,它给了我一个编译器错误。我不确定为什么,因为函数的返回值与引用的生命周期无关,我觉得它应该是独立的。有人可以帮我重构这个吗?

我得到的错误是

  --> src\ui\song_editor_cli.rs:15:66
   |
15 |         if let Some(res) = choice_ui::ui_offer_choices(&choices, editor) {
   |                                                        --------  ^^^^^^ `*editor` was mutably borrowed here in the previous iteration of the loop
   |                                                        |
   |                                                        first borrow used here, in later iteration of loop

我的代码是

pub fn ui(editor: &mut SongEditor) {
    let choices = vec![
        Choice::new("Load Song".to_string(), Box::from(load_ui)),
        Choice::new("Create Song".to_string(), Box::from(create_ui)),
        Choice::new("Edit Song".to_string(), Box::from(edit_ui)),
    ];
    println!("Hello! Welcome to Song Maker!");
    loop {
        if let Some(res) = choice_ui::ui_offer_choices(&choices, editor) {
            if let Err(err) = res {
                println!("{err}");
            }
        }
        else {
            break
        }
    }
    println!("Goodbye from Song Maker!")
}
pub struct Choice<Args, Res> {
    prompt: String,
    callback: Box<dyn Fn(Args) -> Res>
}

impl<Args, Res> Choice<Args, Res> {
    pub fn new(prompt: String, callback: Box<dyn Fn(Args) -> Res>) -> Self {
        Choice {prompt, callback}
    }
    
    pub fn call(&self, args: Args) -> Res {
        (self.callback)(args)
    }
}
pub fn ui_offer_choices<Args, Res>(choices: &Vec<Choice<Args, Res>>, args: Args) -> Option<Res> {
    for (index, choice) in choices.iter().enumerate() {
        println!("\t{}. {}", index + 1, choice.prompt)
    }
    println!("\tq. Quit");
    let mut buf = String::new();
    loop {
        buf.clear();
        io::stdin().read_line(&mut buf).expect("Failed to read user input!");
        let buf = buf.trim();
        if buf == "q" {
            return None;
        }
        let choice_number = buf.parse::<usize>().expect("failed to parse user input as number!") - 1;
        if choice_number < choices.len() {
            return Some(choices[choice_number].call(args));
        }
        else {
            println!("{} was not recognized as an available option! Try again or press 'q' to quit!", choice_number)
        }
    }
}

load_ui、create_ui 和 edit_ui 都有一个类似于 fn func_name(editor &mut SongEditor) -> Result 的签名<(), &'static str>

我尝试让 ui fn 接受一个拥有的可变 SongEditor 并在每次循环中可变地借用它,但这不起作用。我觉得我可以尝试更改我的 ui fns 签名以获取 Rc,但我觉得我对应该如何设计这个以及我的问题所在存在某种根本性的误解。在我在堆栈溢出中看到的类似问题中,通常存在一个返回值,其生命周期与借用的值相关。我不认为这存在于我的用例中,因为我唯一返回的生命周期是静态的。

rust borrow-checker
1个回答
0
投票

我认为你无法按原样完成这项工作。

Args
只能推导为单一类型,对于可变引用将包括生命周期。因此,
choices
的参数具有单一生命周期,它所期望的参数必须与
editor
相同。因此,在循环中,您每次都调用
ui_offer_choices
相同的生命周期,这是不允许的。

您可能需要更改

Choice
以使用
dyn Fn(&mut Args) -> Res
来代替,以便可以将生命周期推迟到调用站点。因此,将所有
Args
更改为
&mut Args
,如在操场上所示。

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