Rust 如何创建一个构建器,该构建器采用的类型为`&;的一个片段实现了AsRef;str`?
我正在调用一个函数,该函数采用Rust 如何创建一个构建器,该构建器采用的类型为`&;的一个片段实现了AsRef;str`?,rust,lifetime,Rust,Lifetime,我正在调用一个函数,该函数采用和[&str]。由于编写[“aa”,“bb”]更方便,因此我决定添加AsRef,而不是&[“aa”,“bb”]: struct Builder<'a> { s: Option<&'a [&'a str]>, } impl<'a> Builder<'a> { fn new() -> Builder<'a> { Builder { s: None }
和[&str]
。由于编写[“aa”,“bb”]
更方便,因此我决定添加AsRef
,而不是&[“aa”,“bb”]
:
struct Builder<'a> {
s: Option<&'a [&'a str]>,
}
impl<'a> Builder<'a> {
fn new() -> Builder<'a> {
Builder { s: None }
}
fn abc<S>(&mut self, s: S) -> &mut Self
where S: AsRef<[&'a str]> + 'a
{
self.s = Some(s.as_ref());
self
}
fn build(&self) -> u32 {
0
}
}
fn main() {
Builder::new().abc([]).build();
}
代码尝试将数组的所有权转移到函数
abc([])
,引用数组(s.as_ref()
),然后丢弃数组,这将留下指向未定义内存的指针。生锈不允许你这么做
我做到了:self.s=Some(不安全的{std::mem::transmute(s.as_ref())})代码>
这是一个非常糟糕的主意。如上所述,您现在有一个对不再存在的数组的引用。该内存允许将来在那里放置任何东西,在最佳情况下,访问指针将导致程序崩溃,但也可能继续执行,但会使用无意义的数据
只有在您了解所有后果时才使用不安全的代码。代码尝试将数组的所有权转移到函数abc([])
,引用数组(s.as_ref()
),然后丢弃数组,这将留下指向未定义内存的指针。生锈不允许你这么做
我做到了:self.s=Some(不安全的{std::mem::transmute(s.as_ref())})代码>
这是一个非常糟糕的主意。如上所述,您现在有一个对不再存在的数组的引用。该内存允许将来在那里放置任何东西,在最佳情况下,访问指针将导致程序崩溃,但也可能继续执行,但会使用无意义的数据
只有当您了解所有后果时才使用不安全的代码。一个解决方法是使Builder
比S
更通用,并成为参数S
的所有者:
struct Builder<S> {
s: Option<S>,
}
impl<'a> Builder<[&'a str; 0]> {
fn new() -> Self {
Builder { s: None }
}
}
impl<'a, S: AsRef<[&'a str]>> Builder<S> {
fn abc<T: AsRef<[&'a str]>>(self, s: T) -> Builder<T> {
Builder {
// copy other fields, x: self.x, ...
// and replace s
s: Some(s)
}
}
fn print_s(&self) {
// example of using s
if let Some(ref s) = self.s {
println!("{:?}", s.as_ref()); // S::as_ref
} else {
println!("None");
}
}
}
解决方法是使Builder
比S
更通用,并成为参数S
的所有者:
struct Builder<S> {
s: Option<S>,
}
impl<'a> Builder<[&'a str; 0]> {
fn new() -> Self {
Builder { s: None }
}
}
impl<'a, S: AsRef<[&'a str]>> Builder<S> {
fn abc<T: AsRef<[&'a str]>>(self, s: T) -> Builder<T> {
Builder {
// copy other fields, x: self.x, ...
// and replace s
s: Some(s)
}
}
fn print_s(&self) {
// example of using s
if let Some(ref s) = self.s {
println!("{:?}", s.as_ref()); // S::as_ref
} else {
println!("None");
}
}
}
如何为str
执行AsRef
implI考虑过这样的建议,但是由于s
被包装在选项中
,因此似乎可以在没有abc
的情况下调用构建器。尝试一下,您将看到无法推断类型。您可以将默认值设置为S
,或者从空数组或其他内容开始。如果您总是需要调用abc
,那么它应该作为构建器构造函数的一部分提供,而且所有这些都更容易。@Lupe您能用一个例子说明您想要什么吗?建议使用匹配和一些(参考编号)
。另外,我认为OP想要通过一个Vec
@Shepmaster,谢谢你的观察。我更新了答案。一个限制是必须逐个复制Builder
的字段。在users.rust-lang.org(我想)上有一个帖子,说如果a:a
和x
具有不同的泛型类型,就不可能执行a{x=2,…a}
,但我现在没有找到它。如何为str
执行AsRef
implI考虑过这样的建议,但是由于s
被包装在选项中
,因此似乎可以在没有abc
的情况下调用构建器。尝试一下,您将看到无法推断类型。您可以将默认值设置为S
,或者从空数组或其他内容开始。如果您总是需要调用abc
,那么它应该作为构建器构造函数的一部分提供,而且所有这些都更容易。@Lupe您能用一个例子说明您想要什么吗?建议使用匹配和一些(参考编号)
。另外,我认为OP想要通过一个Vec
@Shepmaster,谢谢你的观察。我更新了答案。一个限制是必须逐个复制Builder
的字段。在users.rust-lang.org(我想)上有一个帖子,说如果a:a
和x
使用不同的泛型类型,就不可能执行a{x=2,…a}
,但我现在没有找到它。
fn main() {
Builder::new().print_s();
Builder::new().abc([]).print_s();
Builder::new().abc(["a", "b"]).print_s();
Builder::new().abc(&["a", "b", "c"]).print_s();
Builder::new().abc(vec!["a"]).print_s();
}