Ценность слишком рано падает внутри закрытия и комбинатора, пока существует заимствование
Я сталкиваюсь с проблемой, когда значение отбрасывается, пока оно все еще заимствовано внутри Option
, в закрытии, но мне трудно понять, что именно происходит. Чтобы проиллюстрировать, вот рабочий пример того, чего я на самом деле пытаюсь достичь:
fn foo() -> Option<String> {
let hd = match std::env::home_dir() {
Some(d) => d,
None => return None,
};
let fi = match hd.file_name() {
Some(f) => f,
None => return None,
};
let st = match fi.to_str() {
Some(s) => s,
None => return None,
};
Some(String::from(st))
}
Возвращаемое значение-это базовое имя домашнего каталога текущего пользователя внутри Option<String>
.
None => return None,
.
std::env::home_dir()
.and_then(|d| d.file_name())
.and_then(|f| f.to_str())
.map(String::from)
Но rustc обнаруживает a ссылка, которая переживает свою ценность.
error: `d` does not live long enough
--> src/main.rs:33:35
|
33 | .and_then(|d| d.file_name())
| - ^ `d` dropped here while still borrowed
| |
| borrow occurs here
34 | .and_then(|f| f.to_str())
35 | .map(String::from)
| - borrowed value needs to live until here
Я думаю, что это потому, что ссылка в Option<&OsStr>
переживает значение типа PathBuf
. Однако мне все еще трудно понять, как подойти к этому без того, чтобы ценность слишком быстро вышла за рамки.
let x = 42u16.checked_add(1234)
.and_then(|i| i.checked_add(5678))
.and_then(|i| i.checked_sub(90))
.map(|i| i.to_string());
println!("{:?}", x); // Some("6864")
Так что я определенно упускаю из виду несколько вещей, связанных с собственностью в предыдущий пример. Возможно ли это с Option<PathBuf>
?
2 ответа:
Вы правы, что потребляете
PathBuf
, возвращенные изhome_dir()
, но все еще пытаетесь использовать ссылки.Я бы сохранил его в переменной и работал оттуда:
fn foo() -> Option<String> { let path = std::env::home_dir(); path.as_ref() .and_then(|d| d.file_name()) .and_then(|f| f.to_str()) .map(String::from) }
Вызов
path.as_ref()
делаетOption<&PathBuf>
в качестве отправной точки для цепочкиand_then
, не потребляя исходную принадлежащуюPathBuf
, которая необходима по крайней мере доString::from
.
Расширяя ответ Криса: вы также можете исправить проблему, вложив цепочку, начинающуюся со второго
and_then
в замыкание, переданное первомуand_then
. Это работает, потому что он сохраняетd
(которому принадлежитPathBuf
) живым, пока заимствования на нем не будут освобождены.fn foo() -> Option<String> { std::env::home_dir().and_then(|d| { d.file_name() .and_then(|f| f.to_str()) .map(String::from) }) }