如何在Rust中的哈希表中追加字符串值?

时间:2017-03-18 17:03:12

标签: string hashmap rust append memory-efficient

我有源文件包含给定日期的许多产品的文本CSV行。我想使用Rust来整理这些文件,以便最终得到许多新的目标CSV文件,每个产品一个,每个文件包含仅针对该产品的部分行。

我目前的解决方案是循环遍历源文件的行,并使用HashMap<String, String>收集每个产品的行。我拆分每个源代码行并使用包含产品ID的元素作为键,以在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的{​​{1}}添加更多文字,并且我已尽力研究示例线上。令人惊讶的是,在Rust数据结构中操作非数字条目的示例很少。

HashMap<String, String>

尝试编译它会产生以下错误:

// 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

2 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:2)

*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());