Recently I've decided to write a network program that heavily utilizes string dictionary. From the experience of other languages, I expected it has the following two insert methods:
a.insert("key", "value");
let v2 = (1+2).to_string();
a.insert("key2", v2);
This is very natural in GC-based languages, as string variable and string literal has the same type. However in Rust we have &str
and String
. To be more specific, string literals, of type &'static str
.
On the other hand, in C++, global/static const char*
and std::string
also can be different. Anyway the function definition can utilize overloading to achieve the same goal.
After some research, I think the best way to approach it is something like this:
trait HashMapHelper<'a> {
fn ins(&mut self, k: &'a str, v: &'a str);
fn ins2(&mut self, k: &'a str, v: String);
}
impl<'a> HashMapHelper<'a> for HashMap<Cow<'a,str>, Cow<'a,str>> {
fn ins(&mut self, k: &'a str, v: &'a str) {
self.insert(Cow::Borrowed(k),v.into());
}
fn ins2(&mut self, k: &'a str, v: String) {
self.insert(k.into(),v.into());
}
}
But it's obvious that one has to either use L1 or L2 to insert into the HashMap:
let d1:HashMap<String,String> = HashMap::new();
let d2:HashMap<Cow<str>,Cow<str>> = HashMap::new();
d1.insert("k2".into(),v2); //L1
d2.ins2("k2",v2); //L2
The former one requires to add .into()
to each string literals (besides the cloning overhead), while the latter lacks the ability to stick to a single .ins()
method.
Anyway this is usually just a small pain. But when encountered with a program that heavily uses dictionaries, the tiny problem becomes a little more obvious. So I'm posting here for any potential improvements on it. Any suggestion would be appreciated!