1
votes

I've got a function take_head that takes two parameters: a slice, and the number of items in the "head" of the slice (the "head" being the first n items, and the "tail" being everything after the head). It splits the slice into two parts: the head, which it returns, and the tail, which it sets the parameter to. Here's the main function showing how it's used:

fn main() {
    let mut strings = &mut ["a", "b", "c"][..];
    println!("original: {:?}", strings);

    // head should ["a"], and strings should be set to the tail (["b", "c"]).
    let head = take_head(&mut strings, 1);

    println!("head: {:?}", head);    // Should print ["a"].
    println!("tail: {:?}", strings); // Should print ["b", "c"].
}

If I implement take_head like so:

fn take_head<'a>(strings: &mut &'a mut [&'a str], n: usize) -> &'a mut [&'a str] {
    let value = std::mem::replace(strings, &mut []);
    let (head, tail) = value.split_at_mut(n);
    *strings = tail;

    println!("returning head: {:?}", head);
    head
}

it works correctly and outputs:

original: ["a", "b", "c"]
returning head: ["a"]
head: ["a"]
tail: ["b", "c"]

However, if I implement take_head like this:

// Make a convenient trait for slices.
pub trait TakeFrontMut<T> {
    fn take_front_mut(&mut self, n: usize) -> &mut [T];
}

impl<'a, T> TakeFrontMut <T> for &'a mut [T] {
    fn take_front_mut(&mut self, n: usize) -> &mut [T] {
        // It's the same code as before, just in a trait method.
        let value = std::mem::replace(self, &mut []);
        let (head, tail) = value.split_at_mut(n);
        *self = tail;
        return head;
    }
}

fn take_head<'a>(strings: &mut &'a mut [&'a str], n: usize) -> &'a mut [&'a str] {
    let head = strings.take_front_mut(n);
    println!("returning head: {:?}", head);
    head
}

It produces an error:

<anon>:15:24: 15:41 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements [E0495]
<anon>:15     let head = strings.take_front_mut(n);
                                 ^~~~~~~~~~~~~~~~~
<anon>:14:1: 18:2 help: consider using an explicit lifetime parameter as shown: fn take_head<'a>(strings: &'a mut &'a mut [&'a str], n: usize)
 -> &'a mut [&'a str]
<anon>:14 fn take_head<'a>(strings: &mut &'a mut [&'a str], n: usize) -> &'a mut [&'a str] {
<anon>:15     let head = strings.take_front_mut(n);
<anon>:16     println!("returning head: {:?}", head);
<anon>:17     head
<anon>:18 }

Question: Why does the second version produce an error? What's so different that the parser can't determine the appropriate lifetime? I don't understand why it's failing, and I'm not sure what these conflicting requirements are.

Yes, the take_head function is dumb, but it's the simplest MVCE I could make that still captures the same issue as my real code.

1

1 Answers

3
votes

The signature of take_front_mut doesn't specify the correct lifetime for the return value. It should be &'a mut [T], because that's the lifetime of the slice you split. This also requires you to make a change on the trait itself.

pub trait TakeFrontMut<'a, T> {
    fn take_front_mut(&mut self, n: usize) -> &'a mut [T];
}

impl<'a, T> TakeFrontMut<'a, T> for &'a mut [T] {
    fn take_front_mut(&mut self, n: usize) -> &'a mut [T] {
        let value = std::mem::replace(self, &mut []);
        let (head, tail) = value.split_at_mut(n);
        *self = tail;
        return head;
    }
}