提问者:小点点

如何仅在使用Rust的映射中不存在新对象的情况下才将该对象插入到映射中?


我要把C++代码传输到Rust。 这里是原始的C++代码。

#include <map>
#include <string>
#include <cassert>
#include <iostream>

int main() {
    std::map<std::string, int> m {
        { "A", 1 },
        { "B", 2 },
        { "D", 4 },
    };
    // *1
    auto r = m.equal_range("C"); // *2
    if (r.first == r.second) {
        auto const& it = r.first;
        assert(it->first == "D");
        assert(it->second == 4);
        // Let's say creating the object to insert is high cost
        // so it should be created only if the element doesn't exist.
        // Creating the object at *1 is not acceptable because if the element exists,
        // then the created object isn't userd.
        //
        // `it` is hint iterator that point to insertion position.
        // If the object to isnert has the same key as the argument of equal_range (*2)
        // the time complexity is O(1).
        m.emplace_hint(it, "C", 3); 
    }
    for (auto const& kv : m) {
        std::cout << kv.first << ":" << kv.second << std::endl;
    }
}

可运行演示:https://wandbox.org/permlink/4EEZ2JY9KAOK9RU0

这是插入如果不存在模式。

我想存档两个目标。

一个是有效地插入对象。 搜索对象需要O(logN)的时间复杂度。 我只想在映射中不存在新对象的情况下插入该对象。 如果从一开始就插入新对象,那么搜索插入位置需要O(logN)个额外开销。 原始的C++代码使用it作为插入新对象的提示。

另一种是只在映射中不存在具有相同键的对象时才创建新对象。 因为在实际情况下创建对象需要很高的成本。 (我的示例代码用户std::string和int value.这只是一个示例。) 所以,我不想在*1处预先创建要插入的对象。

我读了BTreeMap文档。 但我找不到路。

https://doc.rust-lang.org/std/collections/struct.btreemap.html

有什么好办法可以做到吗? 或者是否有任何非标准容器(map)来支持我想做的操作?


共1个答案

匿名用户

看起来你想要条目API?

在您的示例中,m.Entry(“c”)将返回一个条目枚举,其中包含条目是否存在的信息。 然后,您可以显式分派或使用高级方法之一,例如BTreeMap::or_insert_with,它接受一个函数(从而创建要缓慢插入的对象)

因此,Rust版本的内容大致如下:

let mut m = BTreeMap::new();
m.insert("A", 1);
m.insert("B", 2);
m.insert("D", 4);

m.entry("C").or_insert_with(|| {
    3 // create expensive object here
});

for (k, v) in &m {
    println!("{}:{}", k, v);
}