Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement Borrow, ToOwned, or Deref for an enum?

Tags:

enums

rust

I have a type that looks like this:

enum Name<'a> {
    Single(&'a str),
    Double(&'a str, &'a str),
}

And another, very similar type that looks like this:

enum OwnedName {
    Single(String),
    Double(String, String),
}

I already have a method to convert a Name to an OwnedName. However, I cannot figure out a way to implement something like Deref or Borrow for this type to convert an OwnedName back to a Name. This means I have to write the same methods twice, which is annoying. I’d like to have something that mimics the way PathBuf/Path or String/str work. I’ve tried something like this:

impl ops::Deref for OwnedName {
    type Target = Name;

    fn deref(&self) -> &Name {
        match *self {
            OwnedName::Single(ref s) => Name::Single(&**s),
            OwnedName::Double(ref s1, ref s2) => Name::Double(&**s1, &**s2),
        }
    }
}

This errors with wrong number of lifetime parameters: expected 1, found 0 on type Target = Name, which is completely understandable, as, well, it needs a lifetime. But I can’t provide one. So is there a way for me to use Deref, or Borrow, or ToOwned in this way?

like image 535
Ben S Avatar asked Dec 31 '15 07:12

Ben S


2 Answers

I agree with @DK. Just adding that if your idea is to use them interchangeably, you may not need to have an OwnedName at all. You can define Name to accept both &str and String:

enum Name<T> where T:Borrow<str> {
    Single(T),
    Double(T, T),
}

// these both work now
let _a1 = Name::Single("hello");
let _a2 = Name::Double(String::from("hello"), String::from("world"));
like image 103
Paolo Falabella Avatar answered Oct 19 '22 07:10

Paolo Falabella


There is no way to do this.

Note that Deref::deref's signature says it wants a pointer to a Name with the same lifetime as the thing being deref'ed. Such a value does not exist. You cannot return a pointer to something you created in the deref function, either, since it can't possibly outlive its own stack frame.

The fundamental problem is that Name is basically a different kind of pointer (like *const T is to &T), but Deref and other traits like it only allow you to return borrowed pointers. At present, this is just no way around this.

You can, however, do this if you just don't use Deref and other traits like it. One possibility would be to impl<'a> From<&'a OwnedName> for Name<'a>.

like image 31
DK. Avatar answered Oct 19 '22 09:10

DK.