I'm trying to use the Snowball stemmer crate in Rust to stem a vector of words. It should be simple, but the borrow checker keeps rejecting my code:
// Read user input
let input = stdin();
let mut stemmer = Stemmer::new("english").unwrap();
for line in input.lock().lines() {
let line = line.unwrap();
let mut query: Vec<_> = line.split_whitespace().collect();
for t in &mut query {
*t = stemmer.stem_str(t);
}
// …
}
The borrow checker says I have two mutable borrows of stemmer
on the line *t = stemmer.stem_str(t);
and rejects my code. (Line 80 is where the block of for line in input.lock().lines()
end.)
57 18 error E0499 cannot borrow `stemmer` as mutable more than once at a time (first mutable borrow occurs here) (rust-cargo)
57 18 error E0499 cannot borrow `stemmer` as mutable more than once at a time (second mutable borrow occurs here) (rust-cargo)
80 5 info E0499 first borrow ends here (rust-cargo)
If I call the stem()
method directly, I get a String
, but then I can't just call as_str()
and expect to assign the obtained &str
back to *t
, since the borrow checker complains that the "borrowed value does not live long enough".
57 18 error borrowed value does not live long enough (temporary value created here) (rust-cargo)
57 18 info consider using a `let` binding to increase its lifetime (rust-cargo)
57 42 info temporary value only lives until here (rust-cargo)
80 5 info temporary value needs to live until here (rust-cargo)
I'm not sure if this has something to do with the implementation details of this library, but I really feel stuck here. I never expected stemming a vector of inputs would be so difficult.
From the documentation of
stem_str
:Presumably, this is because the stemmer implementation actually has some kind of internal buffer where the word is stored as it is stemmed.
This is why you cannot call
stem_str
twice while keeping a reference to the string; doing so would invalidate the first string!.The compiler is absolutely correct again. You are attempting to create a value, take a reference to it, store the reference, then drop the value! That's a memory vulnerability and you can't do it.
Instead, collect a vector of
String
s:I'd highly recommend reading The Rust Programming Language and understanding how references work and what they prevent. Do this before and during getting into anything complicated with ownership. These chapters specifically: