我正在调用一个&[&str]
的函数。由于编写["aa", "bb"]
而不是&["aa", "bb"]
更方便,我决定添加AsRef
:
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();
}
但是生命存在问题:
error: `s` does not live long enough
self.s = Some(s.as_ref());
^
note: reference must be valid for the lifetime 'a as defined on the block at 12:4...
{
self.s = Some(s.as_ref());
self
}
note: ...but borrowed value is only valid for the scope of parameters for function at 12:4
{
self.s = Some(s.as_ref());
self
}
答案 0 :(得分:1)
代码尝试将数组的所有权转移到函数abc([])
,引用数组(s.as_ref()
),然后抛弃数组,会留下指向未定义内存的指针。 Rust不允许你这样做。
我做到了:
self.s = Some(unsafe { std::mem::transmute(s.as_ref()) });
这是非常糟糕的主意。如上所述,您现在可以引用不再存在的数组。该内存将来可以放置任何,并且在最佳情况下访问指针会导致程序崩溃,但也可能继续执行但是无意义的数据。
只有在了解所有后果后才能使用unsafe
代码。
答案 1 :(得分:1)
解决方法是让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");
}
}
}
现在可以使用不同的参数类型调用abc
:
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();
}