问题
- I have a bunch of long immutable strings, which I would like to store in a
HashSet
. - I need a bunch of mappings with these strings as keys.
- I would like to use references to these strings as keys in these mappings to avoid copying strings.
This is how I managed to eventually get to this status. The only concern is this extra copy I need to make at line 5.
let mut strings: HashSet<String> = HashSet::new(); // 1
let mut map: HashMap<&String, u8> = HashMap::new(); // 2
// 3
let s = "very long string".to_string(); // 4
strings.insert(s.clone()); // 5
let s_ref = strings.get(&s).unwrap(); // 6
map.insert(s_ref, 5); // 7
playground link
To avoid this cloning I found two workarounds:
- Use
Rc
for string (adds overhead and code clutter) - Use unsafe code
Is there any sensible way to remove this excessive cloning?
回答1:
It seems to me that what you are looking for is String Interning. There is a library, string-cache, which was developed as part of the Servo project which may be of help.
In any case, the basics are simple:
- a long-lived pool of
String
, which guarantees they will not be moving at all - a look-up system to avoid inserting duplicates in the pool
You can use a typed arena to store your String
, and then store &str
to those strings without copying them (they will live for as long as the arena lives). Use a HashSet<&str>
on top to avoid duplicates, and you're set.
来源:https://stackoverflow.com/questions/39205905/safe-and-efficient-way-to-use-string-and-its-pointer-in-different-collections