Reputation: 15
I am calling a function that takes a &[&str]
. As it is more convenient to write ["aa", "bb"]
, instead of &["aa", "bb"]
, I decided to add 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();
}
But there is a problem with lifetime:
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
}
Upvotes: 0
Views: 104
Reputation: 11177
A workaround is to make Builder
be generic over S
and be the owner of parameter 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");
}
}
}
Now abc
can be called with different parameter types:
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();
}
Upvotes: 1
Reputation: 431469
The code tries to transfer ownership of the array to the function abc([])
, take a reference to the array (s.as_ref()
), then it throws away the array, which would leave a pointer to undefined memory. Rust does not allow you to do that.
I did it:
self.s = Some(unsafe { std::mem::transmute(s.as_ref()) });
This is a very bad idea. As mentioned above, you now have a reference to an array that no longer exists. That memory is allowed to have anything placed there in the future, and accessing the pointer will, in the best case, cause your program to crash, but could also continue executing but with nonsense data.
Only use unsafe
code when you understand all the consequences.
Upvotes: 1