Cannot return value referencing function parameter `x`

Here is my code and playground:

pub trait Scalar: Sized {}
impl Scalar for i32 {}

pub trait RowIndex<T: Scalar> {
    type Slice<'a> where Self: 'a;
    fn slice_index(&self, start: usize, end: usize) -> Self::Slice<'_>;
}

impl<T: Scalar> RowIndex<T> for Vec<&Vec<T>> {
    type Slice<'a> = Vec<&'a [T]> where Self: 'a;
    fn slice_index(&self, start: usize, end: usize) -> Self::Slice<'_> {
        self.iter().map(|x| &x[start..end]).collect()
    }
}
fn get_slice(x: Vec<&Vec<i32>>) -> Vec<Vec<&[i32]>> {
    let mut res = Vec::new();
    res.push(x.slice_index(1, 2));
    res.push(x.slice_index(3, 4));
    res
}

[E0515] Error: cannot return value referencing function parameter `x`
    ╭─[command_62:1:1]
    β”‚
 17 β”‚     res.push(x.slice_index(1, 2));
    Β·              ─────────┬─────────  
    Β·                       ╰─────────── `x` is borrowed here
    Β· 
 19 β”‚     res
    Β·     ─┬─  
    Β·      ╰─── returns a value referencing data owned by the current function
────╯

But this function can compile.

fn get_slice2(x: Vec<&Vec<i32>>) -> Vec<Vec<&[i32]>> {
    let mut res = Vec::new();
    res.push(x.iter().map(|x| &x[1..2]).collect());
    res.push(x.iter().map(|x| &x[3..4]).collect());
    res
}

I do not know the difference between get_slice and get_slice2. What am I missing?

Rust Playground

Edit: or maybe, somewhat simpler:

Rust Playground

1 Like

The difference is that in your version, slice_index looks like

fn slice_index<'long: 'short, 'short>(
    this: &'short Vec<&'long Vec<T>>,
    start: usizes,
    end: usize,
) -> Vec<&'short [T]> {

Where as in @steffahn's it's more like

fn slice_index<'long: 'short, 'short>(
    this: &'short Vec<&'long Vec<T>>,
    start: usizes,
    end: usize,
) -> Vec<&'long [T]> {

With the former in get_slice, you're borrowing the local Vec you took as an argument, and that borrow can't outlast the function body (you drop the Vec at the end of the body). With the latter, you're just rearranging the inner borrows you were given.

2 Likes

I though I get what you mean: -> Self::Slice<'_> this return signature let the compile choose the function slice_index return type.
When I call:

let a = vec![1i32, 2, 3];
let b = vec![2, 3, 4];
let x = vec![&a, &b];

x.slice_index(1, 2);

It is actually calling:

<Vec<&'long Vec<i32>> as RowIndex<i32>>::slice_index(&'short Vec<&'long Vec<i32>>, 1, 2)

Maybe because of the compile sees 'short first, the function choose 'short to replace '_ in Slice<'_> rather than 'long. So I get Vec<&'short [i32]>.
But 'short just exits in the function body. So the resulte can not go out of the function.

Elision rules are straightforward and well-defined. In a &self method, elided lifetimes in the return type always refer to the lifetime of the &self borrow. Thus

fn slice_index(&self, start: usize, end: usize) -> Self::Slice<'_>

desugars to

fn slice_index<'short>(&'short self, start: usize, end: usize) -> Self::Slice<'short>
Click for more context/explanation ;-)

In fact, the whole impl block also has another elided lifetime in the Self-type.

impl<T: Scalar> RowIndex<T> for Vec<&Vec<T>> {
    type Slice<'a> = Vec<&'a [T]> where Self: 'a;
    fn slice_index(&self, start: usize, end: usize) -> Self::Slice<'_> {
        self.iter().map(|x| &x[start..end]).collect()
    }
}

More explicitly but still elided:

impl<T: Scalar> RowIndex<T> for Vec<&'_ Vec<T>> {
    type Slice<'a> = Vec<&'a [T]> where Self: 'a;
    fn slice_index(&'_ self, start: usize, end: usize) -> Self::Slice<'_> {
        self.iter().map(|x| &x[start..end]).collect()
    }
}

we can discuss the whole desugaring. There are three elided lifetimes (the three '_s), two of them in an β€œinput” position and on in an β€œoutput” position (the output one is the Self::Slice<'_>. Both β€œinput” lifetimes are introduced as a new generic argument

impl<'long, T: Scalar> RowIndex<T> for Vec<&'long Vec<T>> {
    type Slice<'a> = Vec<&'a [T]> where Self: 'a;
    fn slice_index<'short>(&'short self, start: usize, end: usize) -> Self::Slice<'_> {
        self.iter().map(|x| &x[start..end]).collect()
    }
}

and the output lifetime is chosen following the rule to take the lifetime of β€œ&self” (or &mut self), or otherwise the only input lifetime on the same function, or otherwise error. The first case applies, so 'short is chosen.

impl<'long, T: Scalar> RowIndex<T> for Vec<&'long Vec<T>> {
    type Slice<'a> = Vec<&'a [T]> where Self: 'a;
    fn slice_index<'short>(&'short self, start: usize, end: usize) -> Self::Slice<'short> {
        self.iter().map(|x| &x[start..end]).collect()
    }
}

finally, we can also desugar the &'short self to self: &'short Self and replace Self by the actual Self-type as well as Self::Slice<'short> by its definition, to get

impl<'long, T: Scalar> RowIndex<T> for Vec<&'long Vec<T>> {
    type Slice<'a> = Vec<&'a [T]> where Self: 'a;
    fn slice_index<'short>(self: &'short Vec<&'long Vec<T>>, start: usize, end: usize) -> Vec<&'short [T]> {
        self.iter().map(|x| &x[start..end]).collect()
    }
}

which matches what @quinedot wrote above. The 'long: 'short bound that @quinedot also wrote is an implicit bound that always exists when a type of the form &'short SomeTypeInvolving<'long> is used, such as the type in the self argument. The only remaining difference is that @quinedot's function above is a free-standing funciton. You can write a freestanding function equivalent to a method in an impl block by transferring all the generic arguments from the impl to the function.


No, elided lifetimes in function signatures do not let the compiler have any choice. It’s merely a convenient notation to abbreviate an equivalent longer alternative with explicit lifetimes. The rules are defined in a way that’s useful in many/most cases, without being overly complicated and without depending on the contents of the function body. The signature is supposed to stay a stable interface and its meaning is supposed to be clear (and unchanged) from the signature alone. (Rust does unfortunately also break this principle occasionally, but in general it’s a very useful thing.)


Also see:

2 Likes

One more asking, If I need the following implementation, what should I do:

impl<T: Scalar> RowIndex<T> for Vec<T> {
    type Slice<'a> =  &'a [T] where Self: 'a;
    fn slice_index<'a>(&self, start: usize, end: usize) -> Self::Slice<'a>
    where
        Self: 'a,
    {
        &self[start..end]
    }
}

Well, that impl fits better with the original trait design. You can actually implement the original one as

pub trait RowIndex<T: Scalar> {
    type Slice<'a> where Self: 'a;
    fn slice_index(&self, start: usize, end: usize) -> Self::Slice<'_>;
}

impl<'s, T: Scalar> RowIndex<T> for Vec<&'s Vec<T>> {
    type Slice<'a> = Vec<&'s [T]> where Self: 'a;
    fn slice_index(&self, start: usize, end: usize) -> Self::Slice<'_> {
        self.iter().map(|x| &x[start..end]).collect()
    }
}

then both should work?

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.