I want to use a HashSet
for quick string lookup, but I can't seem to find a way to pass a string variable to contains
without a compiler error.
refs = HashSet::new();
let first_pass = link_regex.replace_all(&buffer, |caps: &Captures| {
if caps.len() == 2 {
refs.insert(caps.at(2).unwrap());
}
caps.at(1).unwrap().to_owned()
});
let out = ref_regex.replace_all(&first_pass, |caps: &Captures| {
let capture = caps.at(1).unwrap().to_owned();
// only remove if we've seen it before
if refs.contains(capture) {
return "".to_string();
}
capture
});
That causes this error:
src/bin/remove_links.rs:30:26: 30:33 error: mismatched types [E0308]
src/bin/remove_links.rs:30 if refs.contains(capture) {
^~~~~~~
src/bin/remove_links.rs:30:26: 30:33 help: run `rustc --explain E0308` to see a detailed explanation
src/bin/remove_links.rs:30:26: 30:33 note: expected type `&_`
src/bin/remove_links.rs:30:26: 30:33 note: found type `std::string::String`
If I try
refs.contains(&capture)
then I get
src/bin/remove_links.rs:30:17: 30:25 error: the trait bound `&str: std::borrow::Borrow<std::string::String>` is not satisfied [E0277]
src/bin/remove_links.rs:30 if refs.contains(&capture) {
^~~~~~~~
I'm stumped, do I need to do some sort of type cast?
First, let's find out what type refs
has. At the point HashSet::new()
, the compiler can't tell what kinds of things you are going to put into the set, so the type is not clear yet. But the compiler figures it out in this line:
refs.insert(caps.at(2).unwrap());
The expression inside the function call (caps.at(2).unwrap()
) returns a &str
. So we are putting &str
s into the set, thus refs
has the type HashSet<&str>
.
If you now look at the documentation for contains
, you see that it takes some &Q
as argument. There are also some bounds: where T: Borrow<Q>, Q: Hash + Eq
. We can ignore the Hash + Eq
part; it doesn't cause any problems.
So let's focus on the T: Borrow<Q>
. We do know what T
is: &str
. So let's see what impl
of Borrow
there are for &str
: documentation. We'll find many generic impls, the important of which are (removed some noise):
impl<T> Borrow<T> for T
impl<T> Borrow<T> for &T
So pattern matching our &str
with the right hand pattern, we conclude that for &str
, Borrow<&str>
and Borrow<str>
are implemented. So our Q
could be str
for example. That means that contains
receives a parameter of type &str
(remember the &Q
from above).
capture
however, is of type String
. &capture
is an expression of type &String
. Whenever such an expression is used in a position where a &str
is needed without doubt, the compiler knows how to turn &String
into &str
(deref coercion). In this case however, the situation is not that clear, since we take a detour through the Borrow
trait. Therefore we have to explicitly convert the String
into a &str
. There are a quazzilion ways to achieve this, but how about as_str()
? So the ...
if refs.contains(capture.as_str()) {
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With