Вот 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
Эта ошибка уже подробно описана в другом месте по переполнению стека:
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)
})
});
Это устраняет потенциальную панику и улучшаетэффективность кода.