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.
ignoring the alternative options to return something pointing to a shared static/global thing, or to leak memory ↩︎
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.