Как использовать contains () и retain () со строкой? - PullRequest
0 голосов
/ 29 мая 2018

Я пытаюсь использовать метод 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?

1 Ответ

0 голосов
/ 29 мая 2018

Вот 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)
    })
});

Это устраняет потенциальную панику и улучшаетэффективность кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...