Map Function and Lifetime with Vector vs. Slice

I’m a newbie with Rust so apologies if this seems obvious. Consider the following code:


// borrow values
#[derive(Clone, Debug)]
struct Attribute<'a> {
  name: &'a str,
  value: &'a str,
}

#[derive(Clone, Debug)]
struct OwnedAttribute {
  name: String,
  value: String,
}

impl OwnedAttribute {
  pub fn borrow(&self) -> Attribute {
    Attribute {
      name: &*self.name,
      value: &*self.value,
    }
  }
}

fn main() {
  let v1 = OwnedAttribute { 
    name: "foo".to_string(),
    value: "bar".to_string(),
  };
  let a: Vec<OwnedAttribute> = vec![v1];
  // This is OK
  let b: Vec<Attribute> = a.as_slice().into_iter().map(|v| v.borrow()).collect();
 // error: `v` does not live long enough
 // let b: Vec<Attribute> = a.into_iter().map(|v| v.borrow()).collect();
  println!("{:?}", b);
}

As you can see, if I use as_slice() on the vector, everything is OK. If I use the vector directly via into_iter(), I get an error that the value in my map does not live long enough.

I’m still trying to understand Rust lifetimes. But is it simply the case that in the Vec::into_iter() function, a new object is created for each iteration hence when it is passed into the map function it only has the lifetime of that single iteration? In the the as_slice() case the iterable object is the actual object from the slice and therefore has a longer lifetime?

into_iter() on the Vec destroys the vector as it iterates, so vector’s elements really don’t live past each iteration of the loop.

into_iter() on a slice just destroys the temporary slice (a view into the vector), so elements that were in the original vector remain where they were.

as_slice().into_iter() can be simplified down to .iter().

So what is the object being pass into the map function? Is it the vector’s elements, but since Vec::into_iter() destroys the vector, the compiler knows the lifetime is limited to the loop?

map is receiving OwnedAttribute (i.e. the value itself) - since the value dies after map returns (since you’re not moving it anywhere where it can be retained), you cannot borrow() from it (that’s what the error message means by “v does not live long enough”.

Doesn’t map in the as_slice().into_iter() case also receiving an OwnedAttribute value? But in that case, I can call borrow().

I think @kornel is right in that the difference is that the Vec::into_iter() destroys the vector and hence the elements. In the slice case, it also passes the values into map. But the original vector still exists after the slice is destroyed by the iteration. So the compiler determines that the elements can still be accessed, hence the call to borrow() is valid?

The slice is a reference, so when you iterate it, all you can get is more references. &[T] gives &T elements, not T.

That’s generally true for all things accessed by reference in Rust (exceptions being values that are Copy, and special cases like Option.take()).

No, you’re receiving a &OwnedAttribute in that case because you’re only borrowing from the vector (slice, to be exact), whereas Vec::into_iter is consuming the Vec and transferring ownership of its values to you.

OK. I keep forgetting that unlike some other languages, you can use the same syntax for references and objects.

Thanks for clarifications.