Borrow-checking with Cow

use std::borrow::Cow;

fn test(text: Cow<str>) -> Cow<str> {
    let res = Cow::Borrowed(text.as_ref());
    match res {
        Cow::Borrowed(a) => text,
        owned => owned, // this works: Cow::Owned(own) => Cow::Owned(own)
    }
}

compiler output:

error[E0505]: cannot move out of `text` because it is borrowed
 --> src/lib.rs:7:29
  |
4 | fn test(text: Cow<str>) -> Cow<str> {
  |         ---- has type `std::borrow::Cow<'1, str>`
5 |     let res = Cow::Borrowed(text.as_ref());
  |                             ---- borrow of `text` occurs here
6 |     match res {
7 |         Cow::Borrowed(a) => text,
  |                             ^^^^ move out of `text` occurs here
8 |         owned => owned,
  |                  ----- returning this value requires that `text` is borrowed for `'1`

error[E0515]: cannot return value referencing function parameter `text`
 --> src/lib.rs:8:18
  |
5 |     let res = Cow::Borrowed(text.as_ref());
  |                             ---- `text` is borrowed here
...
8 |         owned => owned,
  |                  ^^^^^ returns a value referencing data owned by the current function

Is there any particular reason that the example only works with Cow::Owned(own) => Cow::Owned(own)?

This does not outlive the function.
Think of res: Cow<'local, str>.

This ties the lifetime of the return type to res:
res imoved to owened , keeping the same type Cow<'local, str>.

Writing Cow::Owned(own) => Cow::Owned(own) destructures res freeing up the lifetime, which is now no longer
Cow<'local, str>, but infered to be Cow<'input, str>.

1 Like

That made me realize that my assumption that as_ref's return type is &'t str (Cow<'t, str>), was wrong, because it also might give the reference to the owned variant. :pensive:

Yeh, thanks.

1 Like