我正在尝试使用retain(...)
方法过滤掉矢量中的值。按照目前的情况,我的代码到目前为止
let results = get_data(); // Returns Result<Vec<MyData>, Box<Error>>
match results {
Ok(mut my_data) => {
// Make sure that `name` is not None
myData.retain(|ref d| d.name.is_some());
// Only keep data if 'name' is in this list
let names = ["Alice", "Bob", "Claire"];
my_data.retain(|ref d| names.contains(d.name.unwrap().as_str()));
},
Err(_) => {}
}
然而,这会产生错误
|
| my_data.retain(|ref d| names.contains(d.name.unwrap().as_str()));
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected &str, found str
|
= note: expected type `&&str`
found type `&str`
似乎编译器在这里告诉我两个不同的东西,但在这两种情况下它似乎都需要一个额外的参考。但是,当我尝试将相关行更改为&names.contains(d.name.unwrap().as_str())
时,编译器会抛出以下错误。
|
| my_data.retain(|ref d| names.contains(&d.name.unwrap().as_str()));
| ^ cannot move out of borrowed content
如何检查借用的String
(我认为name.unwrap()
的类型是什么)是否包含在names
向量中?
答案 0 :(得分:6)
以下是您问题的MCVE(原始代码中包含其他无关的问题,在此处忽略):
struct MyData {
name: Option<String>,
}
fn main() {
let mut my_data: Vec<MyData> = vec![];
// Only keep data if 'name' is in this list
let names = ["Alice", "Bob", "Claire"];
my_data.retain(|ref d| names.contains(d.name.unwrap().as_str()));
}
error[E0308]: mismatched types
--> src/main.rs:10:43
|
10 | my_data.retain(|ref d| names.contains(d.name.unwrap().as_str()));
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected &str, found str
|
= note: expected type `&&str`
found type `&str`
如错误消息所述,slice::contains
需要引用切片中包含的值类型:
pub fn contains(&self, x: &T) -> bool
where
T: PartialEq<T>,
由于切片包含字符串文字(类型为&'static str
),因此需要&&str
进行比较。我们将参考as_str
方法的结果:
my_data.retain(|ref d| names.contains(&d.name.unwrap().as_str()));
// ^-- added
error[E0507]: cannot move out of borrowed content
--> src/main.rs:10:44
|
10 | my_data.retain(|ref d| names.contains(&d.name.unwrap().as_str()));
| ^ cannot move out of borrowed content
此错误已在Stack Overflow上的其他地方详细说明:
TL; DR - 您不拥有d
,因此您无法解开d.name
,从而消耗了此过程中的值。解决方法是使用Option::as_ref
:
my_data.retain(|ref d| names.contains(&d.name.as_ref().unwrap().as_str()));
// ^^^^^^^^^-- added
然而,需要unwrap
是丑陋的,并且理想情况下可以避免。您可以将两个retain
调用合并为一个,使用Option::map_or
跳过展开:
my_data.retain(|d| {
d.name.as_ref().map_or(false, |name| {
let name = name.as_str();
names.contains(&name)
})
});
这消除了潜在的恐慌并提高了代码的效率。