我有一个以常量形式定义的数组,在任何函数之外:
const VALUES: [(char, &str); 2] = [('A', "abc"), ('B', "acb")];
我正在尝试使用 find()
方法位于 Iterator
, 为了根据谓词从数组中提取单个元素:
VALUES.iter().find(|&&(name, _)| name == 'A');
在这种形式下,它工作正常。但是,一旦我尝试创建 let
,我就无法将找到的元素评估为任何东西。绑定(bind),尝试绑定(bind)结果,根据文档,结果应该作为 Option<T>
返回.
让我们将第二行更改为不起作用的行:
const VALUES: [(char, &str); 2] = [('A', "abc"), ('B', "acb")];
fn main() {
let result = VALUES.iter().find(|&&(name, _)| name == 'A');
}
( Playground )
人们会期望这会返回 Option<T>
根据文档,但我得到了一个编译错误:
error: borrowed value does not live long enough
--> src/main.rs:4:63
|
4 | let result = VALUES.iter().find(|&&(name, _)| name == 'A');
| ------ temporary value created here ^ temporary value dropped here while still borrowed
5 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
我完全糊涂了;我确定我刚刚搞砸了“借用检查器”。也许有人可以指出我正确的方向?
最佳答案
问题在于您将该数组转换为迭代器的具体方式。
首先,Rust 中的 const
实际上并不存在于任何地方。相反,它们在使用它们的任何地方都被值替换。因此,每次您使用常量时,您都会得到它的一个新副本。
其次,您正在使用 IntoIterator::into_iter
。这将 按值 获取主题并将其转换为迭代器。
这些与第三部分相结合:IntoIterator
不是为固定大小的数组实现的。它仅针对指向固定大小数组的指针 实现。因此,为了调用 into_iter
,编译器必须插入对调用者的自动借用。
所以,实际发生的是这样的:
let t = {
// Make a new copy of `VALUES`.
let values: [(char, &str); 5] = VALUES;
// Borrow it.
let values: &[_] = &values;
// Call `into_iter` on the borrow.
IntoIterator::into_iter(values).find(|&&(name, _)| name == 'A')
};
这会导致问题,因为编译器必须同时复制 和 借用 VALUES
以获得迭代器。与所有临时对象一样,所述副本的生命周期与语句一样长,但借用(通过绑定(bind)到变量)的生命周期必须长于该语句。
最好的解决方案是使 VALUES
成为数组的指针。这样可以防止复制整个数组;相反,您只需在每次使用时复制指针。
const VALUES: &[(char, &str)] = &[...];
或者,您可以显式复制 VALUES
并将其存储在变量中,然后在那个 上使用into_iter
。但是,和以前一样,这会引入不必要的复制。
关于arrays - 尝试 const 数组中的 .find() 值时如何修复 "temporary value dropped here while still borrowed"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44614193/