Reference 如何使用'AsRef'参数?

Reference 如何使用'AsRef'参数?,reference,rust,lifetime,borrow-checker,borrowing,Reference,Rust,Lifetime,Borrow Checker,Borrowing,我很难让AsRef以干净的方式工作 常量默认值:&str=“lib”; 使用std::path::{path,PathBuf}; fn扩展(p:&Path,q:Option)->PathBuf{ 设q:&Path=q.unwrap_或(默认为.as_ref()); p、 加入(q) } //不编译 fn extend1(p:p,q:Option)->PathBuf{ 设q:&Path=q.map(| x | x.as_ref()).unwrap_或(默认值.as_ref()); p、 as_re

我很难让
AsRef
以干净的方式工作

常量默认值:&str=“lib”; 使用std::path::{path,PathBuf}; fn扩展(p:&Path,q:Option)->PathBuf{ 设q:&Path=q.unwrap_或(默认为.as_ref()); p、 加入(q) } //不编译 fn extend1(p:p,q:Option)->PathBuf{ 设q:&Path=q.map(| x | x.as_ref()).unwrap_或(默认值.as_ref()); p、 as_ref().连接(q) } //不编译 fn extend2(p:p,q:Option)->PathBuf{ 让q:&Path=匹配q{ 一些(x)=>x.作为_ref(), None=>DEFAULT.as_ref(), }; p、 as_ref().连接(q) } fn extend3(p:p,q:Option)->PathBuf{ 匹配q{ Some(x)=>p.as_ref().join(x.as_ref()), None=>p.as_ref().join(AsRef:::as_ref(默认)), } } 函数
extend
Path
引用一起工作,但我想将其概括为接受
AsRef
类型的参数,以便也允许字符串

我的第一次尝试,
extend1
extend2
,没有通过借用检查器,这两种情况下都会抱怨
x
的使用寿命

我的第三次尝试,
extend3
,虽然有效,但存在代码重复的明显缺点,随着函数体的增长,代码重复会变得更加严重


在这种情况下,最好的解决方案是什么?

Option::map
使用内部值(如果有)。因此在code
q.map(|x | x.as_ref())
中,闭包按值取
x
。您可以通过注意
q.map(|x:&q|x.as|u ref())
给出类型错误来检查这一点,而
q.map(|x:q|x.as|u ref())
没有(它仍然给出生存期错误)。这意味着当您调用
x.as_ref()
时,将创建一个对x的新引用,而与任何外部引用无关。这意味着引用仅在闭包内有效,但您希望在
extend1
的其余部分中使用它

您要做的是借用
q
,它在
extend1
结束之前有效。使用
选项::as_ref()
选项
转换为
选项
(只需使用
q.as_ref()
即可创建所需的
q
的借用),即可将
q
的借用转换为
的内容(如果有)。然后,当您使用map时,闭包将采用
&Q
,而不是
Q
。引用的生存期将与
q
的外部借用相同,因此它将持续到
extend1
结束(如果需要)

常量默认值:&str=“lib”; 使用std::path::{path,PathBuf}; fn extend1(p:p,q:Option)->PathBuf{ 设q:&Path=q.as_ref().map(| x | x.as_ref()).unwrap_或(默认值.as_ref()); p、 as_ref().连接(q) }

由于函数的参数仅通过引用使用,因此您可能希望仅通过引用使用它们。这就像在每个参数中添加一个符号一样简单

const DEFAULT: &str = "lib";

use std::path::{Path, PathBuf};

fn extend1<P: AsRef<Path>, Q: AsRef<Path>>(p: &P, q: &Option<Q>) -> PathBuf {
    let q: &Path = q.as_ref().map(|x| x.as_ref()).unwrap_or(DEFAULT.as_ref());
    p.as_ref().join(q)
}
常量默认值:&str=“lib”; 使用std::path::{path,PathBuf}; fn extend1(p:&p,q:&Option)->PathBuf{ 设q:&Path=q.as_ref().map(| x | x.as_ref()).unwrap_或(默认值.as_ref()); p、 as_ref().连接(q) }

常量默认值:&str=“lib”; 使用std::path::{path,PathBuf}; fn extend1(p:&p,q:Option)->PathBuf{ 设q:&Path=q.map(| x | x.as_ref()).unwrap_或(默认值.as_ref()); p、 as_ref().连接(q) }


请注意,最新版本不需要调用
q.as_ref()
,因为
q
已经有type
选项
。此版本最接近您原来的
extend
功能。

谢谢,现在我对它有了更好的理解。不过,我认为我更喜欢您给出的第一个实现,而不是第二个和第三个,因为它更通用:它还接受
选项
选项
。你对这三个版本的选择有什么看法?对我来说,第三个选项似乎是最好的,因为它更明确地说明了克隆路径的事实(因为它不可能重用任何一个参数)。它仍然是通用的,因为如果需要的话,在调用站点(例如
extend1(&string,option\u string.as\u ref())
)可以很容易地借用。不过,这取决于你。与
Path::join
的一致性很好,尽管我可能希望名为“extend”的函数采用可变引用并更改原始
Path
对象(与原始对象相比)。
const DEFAULT: &str = "lib";

use std::path::{Path, PathBuf};

fn extend1<P: AsRef<Path>, Q: AsRef<Path>>(p: &P, q: &Option<Q>) -> PathBuf {
    let q: &Path = q.as_ref().map(|x| x.as_ref()).unwrap_or(DEFAULT.as_ref());
    p.as_ref().join(q)
}
const DEFAULT: &str = "lib";

use std::path::{Path, PathBuf};

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)
}