WedX - журнал о программировании и компьютерных науках

Как добавить строковые значения в хеш-таблицу в Rust?

У меня есть исходные файлы, содержащие текстовые CSV-строки для многих продуктов за определенный день. Я хочу использовать Rust для сопоставления этих файлов, чтобы в итоге у меня было много новых целевых CSV-файлов, по одному для каждого продукта, каждый из которых содержит части строк, характерные только для этого продукта.

Мое текущее решение состоит в том, чтобы перебирать строки исходных файлов и использовать HashMap<String, String> для сбора строк для каждого продукта. Я разделяю каждую исходную строку и использую элемент, содержащий идентификатор продукта, в качестве ключа, чтобы получить Entry (занято или свободно) в моем HashMap. Если он свободен, я инициализирую значение новым String, который выделяется заранее с заданной емкостью, чтобы впоследствии я мог эффективно добавлять к нему.

// so far, so good (the first CSV item is the product ID)
let mystringval = productmap.entry(splitsource[0].to_owned()).or_insert(String::with_capacity(SOME_CAPACITY));

Затем я хочу добавить отформатированные элементы той же исходной строки к этому Entry. В Интернете есть много примеров, например
https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.entry
как заставить это работать, если значение HashMap является целым числом:

// this works if you obtain an Entry from a HashMap containing int vals
*myval += 1;

Я не понял, как добавить больше текста к Entry, который я получаю от своего HashMap<String, String>, используя такой синтаксис, и я сделал все возможное, чтобы найти примеры в Интернете. На удивление мало примеров манипулирования нечисловыми записями в структурах данных Rust.

// using the Entry obtained from my first code snippet above
*mystringval.push_str(sourcePortion.as_str());

При попытке скомпилировать выдает следующую ошибку:

error: type `()` cannot be dereferenced
   --> coll.rs:102:17
    |
102 |                 *mystringval.push_str(sourcePortion.as_str());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Как я могу добавить String внутри значения Entry?


  • Просто mystringval.push_str(sourcePortion.as_str()) должно работать. Не могли бы вы попробовать? 18.03.2017
  • Да, это так. Думаю, меня удивляет, что все примеры изменения записи HashMap, которые я вижу, включают символ разыменования. Не могли бы вы написать ответ, в котором указано, почему в моем случае это не нужно? Я буду рад отметить его как принятый. 18.03.2017

Ответы:


1

*mystringval.push_str(sourcePortion.as_str()); анализируется как *(mystringval.push_str(sourcePortion.as_str()));, и поскольку String::push_str возвращает (), вы получаете ошибку () cannot be dereferenced.

Использование круглых скобок вокруг разыменования решает проблему приоритета:

(*mystringval).push_str(sourcePortion.as_str());

Причина, по которой *myval += 1 работает, заключается в том, что унарный * имеет более высокий приоритет, чем +=, что означает, что он анализируется как

(*myval) += 1

Поскольку or_insert возвращает &mut V, вам не нужно разыменовывать его перед вызовом его методов. Также работает следующее:

mystringval.push_str(sourcePortion.as_str());
18.03.2017

2

Если вы проверите тип, возвращаемый or_insert:

fn update_count(map: &mut HashMap<&str, u32>) {
    let () = map.entry("hello").or_insert(0);
}

Вы увидите, что это изменяемая ссылка:

error[E0308]: mismatched types
 --> src/main.rs:4:9
  |
4 |     let () = map.entry("hello").or_insert(0);
  |         ^^ expected &mut u32, found ()
  |
  = note: expected type `&mut u32`
             found type `()`

Это означает, что вы можете вызывать любой метод, которому нужен приемник &mut self, без дополнительного синтаксиса:

fn update_mapping(map: &mut HashMap<&str, String>) {
    map.entry("hello").or_insert_with(String::new).push_str("wow")
}

Возвращаясь к целочисленной форме, что произойдет, если мы не поместим разыменование?

fn update_count(map: &mut HashMap<&str, i32>) {
    map.entry("hello").or_insert(0) += 1;
}
error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut i32`
 --> src/main.rs:4:5
  |
4 |     map.entry("hello").or_insert(0) += 1;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use `+=` on type `&mut i32`

error[E0067]: invalid left-hand side expression
 --> src/main.rs:4:5
  |
4 |     map.entry("hello").or_insert(0) += 1;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid expression for left-hand side

Разница в том, что оператор += автоматически принимает изменяемую ссылку на левую часть выражения. В развернутом виде это может выглядеть примерно так:

use std::ops::AddAssign;

fn update_count(map: &mut HashMap<&str, i32>) {
    AddAssign::add_assign(&mut map.entry("hello").or_insert(0), 1);
}

Добавление явного разыменования возвращает типы к типу, в котором реализован трейт:

use std::ops::AddAssign;

fn update_count(map: &mut HashMap<&str, i32>) {
    AddAssign::add_assign(&mut (*map.entry("hello").or_insert(0)), 1);
}
18.03.2017
  • Спасибо за подробный ответ, @Shepmaster 18.03.2017
  • @ezekiel68 обязательно проголосуйте за все полезные ответы, даже те, которые вы приняли. 18.03.2017
  • ты еще сделаешь из меня приличного гражданина stackoverflow! 18.03.2017
  • @ezekiel68 мы здесь все об этих волшебных интернет-точках! 18.03.2017
  • Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]