Два изменчивых заимствования происходят на одной линии?
Я пытаюсь использовать ящик для снежного кома в Rust, чтобы остановить вектор слов. Это должно быть просто, но средство проверки заимствований продолжает отклонять мой код:
// 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);
}
// …
}
Проверка заимствования говорит, что у меня есть два изменяемых заимствования stemmer
на линии *t = stemmer.stem_str(t);
и отклоняет мой код. (Строка 80, где блок for line in input.lock().lines()
конец.)
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)
Если я позвоню stem()
метод напрямую, я получаю String
, но тогда я не могу просто позвонить as_str()
и ожидаем назначить полученное &str
вернуться к *t
, поскольку контролер заимствований жалуется, что "заимствованная стоимость не живет достаточно долго".
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)
Я не уверен, что это как-то связано с деталями реализации этой библиотеки, но я действительно чувствую себя здесь застрявшим. Я никогда не ожидал, что остановить вектор входных данных будет так сложно.
1 ответ
Из документацииstem_str
:
Ссылка str, которую она возвращает, действительна только до тех пор, пока вы не вызовете stem или stem_str снова; таким образом, заемщик Rust не позволит вызвать одну из них, если у вас есть такая ссылка в области видимости.
Предположительно, это потому, что реализация стеммера на самом деле имеет своего рода внутренний буфер, в котором слово хранится в том виде, в котором оно содержится.
Вот почему вы не можете позвонить stem_str
дважды, сохраняя ссылку на строку; это сделает недействительной первую строку!
Я не могу просто позвонить
as_str()
и ожидаем назначить полученное&str
вернуться к*t
Компилятор снова абсолютно прав. Вы пытаетесь создать значение, взять ссылку на него, сохранить ссылку, а затем удалить значение! Это уязвимость памяти, и вы не можете сделать это.
Вместо этого соберите вектор String
s:
for line in input.lock().lines() {
let line = line.unwrap();
let mut query: Vec<_> = line.split_whitespace()
.map(|t| stemmer.stem(t))
.collect();
}
Я очень рекомендую прочитать The Rust Programming Language и понять, как работают ссылки и что они предотвращают. Делайте это до и во время чего-то сложного с владением. Эти главы специально: