How to implement Borrow for my own struct?

Maybe I am not understanding the reason behind the Borrow trait, but shouldn't I be able to implement something like this?

use std::borrow::Borrow;

struct Owned(Vec<u8>);
struct Borrowed<'a>(&'a [u8]);

impl Borrow<Borrowed<'_>> for Owned {
    fn borrow(&self) -> &Borrowed<'_> {
        &Borrowed(&self.0[..])
    }
}

fn main() {
    let owned = Owned(vec![1, 2, 3]);
    let borrow: &Borrowed = owned.borrow();
}

Maybe the problem is with the lifetimes, but I couldn't find a way to solve that. Someone has any idea on what is wrong with this code?

The error the compiler gives to me is the following:

error: `impl` item signature doesn't match `trait` item signature
   --> src/main.rs:8:5
    |
8   |     fn borrow(&self) -> &Borrowed<'_> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Owned) -> &'1 Borrowed<'1>`
    |
    = note: expected `fn(&'1 Owned) -> &'1 Borrowed<'3>`
               found `fn(&'1 Owned) -> &'1 Borrowed<'1>`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output

The return type you’re trying to create, &Borrowed<'_> where Borrowed<'a> contains yet another level of reference &'a [u8] is essentially trying to create a double indirection – like &&[u8] – from a single indirection &Owned (which is like &Vec<u8>). Okay, admitted, Vec is also another layer of indirection, but the point is: it does not contain a &[u8], so there’s no existing &[u8] that the &&[u8] you want to return could point to.

In general, the Borrow trait is indeed somewhat limiting by the fact that it has to return a reference (whose lifetime is tied to the lifetime of the reference passed in), so essentially, every Borrow implementation can [1] only return a reference to something that already exists as part of what’s passed in. So creating a new Borrowed struct is not an option.


  1. ignoring the alternative options to return something pointing to a shared static/global thing, or to leak memory ↩︎

That makes sense, I was having the impression that my approach was wrong, but I didn't realize the double indirection problem. Thanks a lot!

Well, double indirection is perfectly fine and it's not the problem in itself. The problem here is that the signature of Borrow::borrow() requires you to return a reference, but you can only return a reference to something that is already owned. You can't return a reference to a value created inside the function you are trying to return from.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.