2
votes

I have a struct that wraps some functionality around a slice:

use std::fmt::Debug;

struct SliceWrapper<'a, T: Debug + Copy + 'a> {
    slice: &'a [T],
    pos: usize,
}

I want to implement the From trait for each element that supports AsRef<T: Debug + Copy + 'a> like this:

impl<'a, T: Debug + Copy + 'a, R: AsRef<[T]> + 'a> From<R> for SliceWrapper<'a, T> {
    fn from(slice: R) -> Self {
        Self {
            slice: slice.as_ref(),
            pos: 0,
        }
    }
}

I get the error:

error[E0597]: `slice` does not live long enough
  --> src/lib.rs:11:20
   |
11 |             slice: slice.as_ref(),
   |                    ^^^^^ borrowed value does not live long enough
...
14 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 8:6...
  --> src/lib.rs:8:6
   |
8  | impl<'a, T: Debug + Copy + 'a, R: AsRef<[T]> + 'a> From<R> for SliceWrapper<'a, T> {
   |      ^^

I don't understand this because I say that R (slice) must live as long as my SliceWrapper – and as far as I understand it, AsRef<_> inherits the lifetime from it's self (slice)...

2

2 Answers

3
votes

The full error message on nightly states quite clearly what's happening here. You move slice into the function from(), then borrow it using as_ref(), and then it gets dropped at the end of the scope:

8  | impl<'a, T: Debug + Copy + 'a, R: AsRef<[T]> + 'a> From<R> for SliceWrapper<'a, T> {
   |      -- lifetime `'a` defined here
9  |     fn from(slice: R) -> Self {
10 |         Self{ slice: slice.as_ref(), pos: 0 }
   |                      ^^^^^---------
   |                      |
   |                      borrowed value does not live long enough
   |                      argument requires that `slice` is borrowed for `'a`
11 |     }
   |     - `slice` dropped here while still borrowed

You are trying to create a borrow that lives for the lifetime 'a, but the owner you are borrowing from, slice, does not live long enough.

The From trait does not seem to be a good fit for this use case. The idea of that trait is to move ownership of some data to a new type, but your SliceWrapper does not take ownership. I suggest writing a custom constructor instead that takes R by reference.

1
votes

You can restrict the conversion to reference arguments, and then you have a nice way to express the borrowing you need — lifetime is taken from the input reference:

impl<'a, T, R> From<&'a R> for SliceWrapper<'a, T>
where
    T: Debug + Copy + 'a,
    R: AsRef<[T]>
{
    fn from(slice: &'a R) -> Self {
        Self {
            slice: slice.as_ref(),
            pos: 0,
        }
    }
}

Now you can follow your original reasoning. You have AsRef giving you: &'x self -> &'x [T] for any 'x and you input a &'a R into that, so you get a&'a [T] out.

Reference taking From sometimes exist, I think it's especially appropriate in reference-to-reference-like conversions. An example in std is impl<'a> From<&'a str> for Cow<'a, str>