[我很难使AsRef
以干净的方式工作。
const DEFAULT: &str = "lib"; use std::path::{Path, PathBuf}; fn extend(p: &Path, q: Option<&Path>) -> PathBuf { let q: &Path = q.unwrap_or(DEFAULT.as_ref()); p.join(q) } // DOES NOT COMPILE fn extend1<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Option<Q>) -> PathBuf { let q: &Path = q.map(|x| x.as_ref()).unwrap_or(DEFAULT.as_ref()); p.as_ref().join(q) } // DOES NOT COMPILE fn extend2<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Option<Q>) -> PathBuf { let q: &Path = match q { Some(x) => x.as_ref(), None => DEFAULT.as_ref(), }; p.as_ref().join(q) } fn extend3<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Option<Q>) -> PathBuf { match q { Some(x) => p.as_ref().join(x.as_ref()), None => p.as_ref().join(AsRef::<Path>::as_ref(DEFAULT)), } }
extend
函数可与Path
引用一起使用,但我想将其概括为接受AsRef<Path>
类型的参数,以便例如也允许使用字符串。
[我的第一次尝试,extend1
和extend2
没有通过借阅检查器,这两种情况都抱怨x
的生存期。
我的第三次尝试,extend3
,虽然有效,但是具有代码重复的明显缺点,随着功能体的增长,它会变得更加严重。
在这种情况下最好的解决方案是什么?
我很难让AsRef以一种干净的方式工作。 const默认值:&str =“ lib”;使用std :: path :: {Path,PathBuf}; fn extend(p:&Path,q:Option)-> ...
Option::map
使用内部值(如果有一个)。因此,在代码q.map(|x| x.as_ref())
中,闭包按值取x
。您可以通过注意q.map(|x: &Q| x.as_ref())
给出类型错误,而q.map(|x: Q| x.as_ref())
则没有(它仍然给出生命周期错误)来检查此情况。这意味着当您调用x.as_ref()
时,将创建对x的新引用,该引用与任何外部引用都不相关。这意味着该引用仅在闭包内部有效,但您想在extend1
的其余部分中使用它。
您想做的是借用q
,该借用有效期至extend1
结束。可以使用q
将Option::as_ref()
的借项转换为其内容(如果有)的借项,以将&Option<Q>
转换为Option<&Q>
(只需使用q.as_ref()
将创建您需要的q
借项)。然后,当您使用map时,闭包将采用&Q
,而不是Q
。引用的生存期将与q
的外部借用相同,因此它将持续到extend1
的结尾(如果需要)。