I cannot figure out why this code compiles:
fn f(v: &mut Vec<isize>) -> &[isize] {
v.as_mut_slice()
}
and this does not:
fn f(v: &mut Vec<isize>) -> &[isize] {
v.as_slice()
}
producing:
<anon>:2:5: 2:6 error: `v` does not live long enough
<anon>:2 v.as_slice()
^
<anon>:1:38: 3:2 note: reference must be valid for the anonymous lifetime #1 defined on the block at 1:37...
<anon>:1 fn f(v: &mut Vec<isize>) -> &[isize] {
<anon>:2 v.as_slice()
<anon>:3 }
<anon>:1:38: 3:2 note: ...but borrowed value is only valid for the block at 1:37
<anon>:1 fn f(v: &mut Vec<isize>) -> &[isize] {
<anon>:2 v.as_slice()
<anon>:3 }
If I understand correctly, in either case function signature is same, and return value lifetime is equal to the input parameter one. So why "as_slice" does not work?
it's a "bug" or better a limitation of the AsSlice
trait. Since v.as_slice()
is now unstable and will probably be removed in favor of &v[]
(which already works as intended in your case) I will not open a bug, but I'll try explaining why the current trait does not work to the best of my knowledge.
First, look at the definition of the as_slice
that is invoked in your case.
impl<'a, T, U: ?Sized + AsSlice<T>> AsSlice<T> for &'a mut U {
#[inline(always)]
fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) }
}
note that as_slice is actually eliding a new lifetime. If we give it a name ('b
) we're actually writing something like:
impl<'a, T, U: ?Sized + AsSlice<T>> AsSlice<T> for &'a mut U {
#[inline(always)]
fn as_slice<'b>(&'b self) -> &'b [T] { AsSlice::as_slice(*self) }
}
What we would actually want is 'b
to be the same as 'a
, but I think there was no way to express this at the time AsSlice
was created (now this might be possible with Higher Ranked Trait Bounds). The effect of this is that, when we call as_slice()
in your function f
, we're returning a fresh lifetime, that can't escape f
. This is in fact the error you're getting.
If AsSlice
was written now, it would be using associated types and would be able to link lifetimes in the way we want. It would be something similar to this:
pub trait AsSlice2 {
type Item;
fn as_slice_2(&self) -> & [Self::Item];
}
impl<T> AsSlice2 for [T] {
type Item = T;
fn as_slice_2(&self) -> &[T] { &self[] }
}
playpen
This is similar to how as_mut_slice is currently implemented (that's why that one works)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With