rustsliceborrow-checkerborrow

Rust: what is different in the slice clone method?


Coming from this code template which works:

{ 
  fn f3( _s : &String) {}

  fn f( s : &String) -> impl FnMut() {
   let s2 = s.clone();
   move || f3( &s2)
  }

  let mut f2 = f( &"123".to_string());

  f2();
}

If I modify the code this way:

{ 
  fn f3( _s : &[u8]) {}

  fn f( s : &[u8]) -> impl FnMut() {
   // let s2 = s.clone(); // don't work
   let s2 = Vec::from(s);
   move || f3( &s2[..])
  }

  let mut f2 = f( &vec![1u8][..]);

  f2();
}

I cannot use 'let s2 = s.clone();'. This brings the error message:

1169 |   fn f( s : &[u8]) -> impl FnMut() {
     |                       ------------ this return type evaluates to the `'static` lifetime...
1170 |    let s2 = s.clone();
     |               ^^^^^ ...but this borrow...
     |
note: ...can't outlive the anonymous lifetime #1 defined on the function body at 1169:3

How can clone initiate a borrow?


Solution

  • In your first example, s is a &String, and String implements Clone, so the clone(&self) method is used.

    In your second example, s is a &[u8], and [u8] does not implement Clone. So instead you are using the blanket implementation for &T where T is any type; that is, you are cloning the reference, not the thing being referenced. The result is another reference to the same thing, hence it is still a borrow.

    The solution in this case is to use a different method than .clone() to create an owned copy of the slice. As you've noticed, Vec::from works, and gives you a Vec<u8>; you can also use Box::from to get a Box<[u8]>. You can't (currently) get a raw [u8] as a local variable, since that is an unsized type, so the use of ::from here is because you need to choose what other type your owned copy will be.