如何查找或插入 Vec

Chr*_*rce 6 rust borrow-checker

我正在尝试编写一个函数,该函数查找返回对 Vec 中现有元素的可变引用,或者如果它不存在则将其插入并返回对新元素的可变引用。

我已经尝试过几次,但借用检查员并不相信。我已将尝试编写的代码简化为下面的示例,该示例给出了相同的错误。

fn mut_find_or_insert<T: PartialEq>(vec: &mut Vec<T>, val: T) -> &mut T {
    if let Some(u) = vec.iter_mut().find(|u| **u == val) {
        u
    } else {
        vec.push(val);
        vec.last_mut().unwrap()
    }
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接:https://play.rust-lang.org/?version= stable&mode=debug&edition=2018&gist=cb12c38bcf3682b15a247d14aab48b6b

Rust 给出了以下编译器错误(通过游乐场链接的完整消息):

error[E0499]: cannot borrow `*vec` as mutable more than once at a time
Run Code Online (Sandbox Code Playgroud)

这似乎应该可以在 Rust 中实现,但是我不清楚如何重新实现它以避免借用检查器错误。

tre*_*tcl 8

这不能按书面方式工作的原因是由于当前借用检查器的限制。这与NLL 情况 #3match非常相似,在这种情况下,当借用仅在其中一个分支中使用时,编译器对整个语句的借用有些过度热心。使用实验性的“Polonius”借用检查器(可在夜间编译器上使用-Z polonius),您的代码将按原样被接受。

\n

在稳定的编译器中工作,重新设计数据结构可能是一个好主意,正如S\xc3\xa9bastien Renauld\ 的答案也建议的那样,但如果您需要使用Vec,您可以通过以下方式解决它简单地使用索引来结束借用:

\n
fn mut_find_or_insert<T: PartialEq>(vec: &mut Vec<T>, val: T) -> &mut T {\n    if let Some(i) = vec.iter().position(|each| *each == val) {\n        &mut vec[i]\n    } else {\n        vec.push(val);\n        vec.last_mut().unwrap()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是有效的,因为调用的结果不是引用,因此在调用期间不会保留 的position借用vecif let

\n

这类似于以下问题,这些问题设法使用循环的早期返回来找到相同的限制:

\n\n