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