Slicing a Cow<str>?

Please see the code segment below with comments:

#![feature(in_band_lifetimes)]
use std::borrow::Cow;

/* if input is borrowed, then return a Cow reference to its first two chars. Pls do not allocate memory.
 * if input is owned, then keep only the first two chars and discard everything else. Pls modify in-place.
 */
fn test(input: Cow<'a, str>)-> Cow<'a, str>{
    Cow::from(&input[0..2])
}

And the error output is:

error[E0515]: cannot return value referencing function parameter `input`
 --> src/main.rs:8:5
  |
8 |     Cow::from(&input[0..2])
  |     ^^^^^^^^^^^-----^^^^^^^
  |     |          |
  |     |          `input` is borrowed here
  |     returns a value referencing data owned by the current function

I must have misunderstood some point of the principle of either the borrow checker or Cow of Rust. Can anyone guide me through this pls?

If the Cow contains a String then your function took ownership of that String. Then you take a reference into that String, but you only return the reference while the String the reference is referring to is dropped at the end of the function. You have to use match on the Cow and either edit the slice or the String. You don't even need to create a new Cow, AFAICT.

3 Likes

That isn’t what is happening here, which is probably why it isn’t compiling when you expect it to.

&input always creates a reference, but Cow has two ways to create it. If the Cow enum variant is a Cow::Owned then it will create a new reference, if it is a Cow::Borrowed then it will effectively copy the existing reference. The relevant bit of code is the match in the Deref implementation for Cow:

fn deref(&self) -> &B {
    match *self {
        Borrowed(borrowed) => borrowed,
        Owned(ref owned) => owned.borrow(),
    }
}

If you want total freedom to do whatever you like depending on whether the data is owned or borrowed (including creating new strings), you could write a match on the Cow enum too.

1 Like