Вставить в hashmap в цикле - PullRequest
0 голосов
/ 30 марта 2020

Я открываю файл CSV и читаю его, используя BufReader, и разбиваю каждую строку на вектор. Затем я пытаюсь вставить или обновить счет в HashMap, используя в качестве ключа указанный столбец c.

let mut map: HashMap<&str, i32> = HashMap::new();

let reader = BufReader::new(input_file);
for line in reader.lines() {
    let s = line.unwrap().to_string();
    let tokens: Vec<&str> = s.split(&d).collect(); // <-- `s` does not live long enough
    if tokens.len() > c {
        println!("{}", tokens[c]);
        let count = map.entry(tokens[c].to_string()).or_insert(0);
        *count += 1;
    }
}

Компилятор сообщает, что s недолговечен. Хранение изнутри al oop заимствованного значения для контейнера во внешней области видимости? предлагает "владеть" строкой, поэтому я попытался изменить

let count = map.entry(tokens[c]).or_insert(0);

на

let count = map.entry(tokens[c].to_string()).or_insert(0);

но я получаю ошибку

expected `&str`, found struct `std::string::String`
help: consider borrowing here: `&tokens[c].to_string()`

Когда я добавляю амперсанд (&), ошибка составляет

creates a temporary which is freed while still in use
note: consider using a `let` binding to create a longer lived

В моих знаниях Rust о заимствованиях есть некоторые недостатки. Как я могу сделать хэш-карту владельцем строки, переданной в качестве ключа?

1 Ответ

1 голос
/ 30 марта 2020

Самый простой способ для этого - ваша карта владеет ключами. Это означает, что вы должны изменить его тип с HasMap<&str, i32> (который заимствует ключи) на HashMap<String, i32>. В этот момент вы можете вызвать to_string, чтобы преобразовать ваши токены в собственные строки:

let mut map: HashMap<String, i32> = HashMap::new();

let reader = BufReader::new(input_file);
for line in reader.lines() {
    let s = line.unwrap().to_string();
    let tokens:Vec<&str> = s.split(&d).collect();
    if tokens.len() > c {
        println!("{}", tokens[c]);
        let count = map.entry(tokens[c].to_string()).or_insert(0);
        *count += 1;
    }
}

Обратите внимание, однако, что это означает, что tokens[c] будет продублировано, даже если оно уже присутствовало на карте. Вы можете избежать дополнительного дублирования, пытаясь сначала изменить счетчик с помощью get_mut, но для этого требуется два поиска, когда ключ отсутствует:

let mut map: HashMap<String, i32> = HashMap::new();

let reader = BufReader::new(input_file);
for line in reader.lines() {
    let s = line.unwrap().to_string();
    let tokens:Vec<&str> = s.split(&d).collect();
    if tokens.len() > c {
        println!("{}", tokens[c]);
        if let Some (count) = map.get_mut (tokens[c]) {
            *count += 1;
        } else {
            map.insert (tokens[c].to_string(), 1);
        }
    }
}

Я не знаю о решение, которое будет копировать ключ только тогда, когда не было предыдущей записи, но по-прежнему будет выполнять один поиск.

...