Enum with a generic type

The problem:

I want to transform AttrType<T1> to AttrType<T2> and i do not necessarily care about which variant it is at that point. How can this be done in a non verbose way without having to match? If it can't, is it worth adding a feature like that?

enum AttrType<T> {
        Meta(T),
        Status(T),
        Content(T),
    }

You can add a method to your enum that does the conversion:

impl AttrType<T1>
{
   fn into_t2(self) -> AttrType<T2> {}
}

Or you can implement std::convert::From

impl From<AttrType<T1>> for AttrType<T2>
...
1 Like

How about using something like

struct AttrType<T> {
    kind: AttrTypeKind,
    payload: T,
}

enum AttrTypeKind {
    Meta,
    Status,
    Content,
}

instead? This would allow e.g.:

impl<T> AttrType<T> {
    fn map<S, F>(self, f: F) -> AttrType<S>
    where
        F: FnOnce(T) -> S
    {
        AttrType {
            kind: self.kind,
            payload: f(self.payload)
        }
    }
}
3 Likes

I still have to match on all the variants.

Well, yes once in your method. You aren't bothered by that in the client code. You have to spell it out once. I don't think there is a way around that apart from separating the variant and the payload like @steffahn showed.

And you can add a type bound so that T2: From<T1>, so you don't need a closure for this.

And if the problem is that you have to do this for many types, you could make a macro to hide the boilerplate.

I like the struct approach. What do you think about having a feature that would allow you to do it without it though? Maybe it would be nice but it's probably too much of a corner case to be worth adding to the language.

I definitely feel this is the case.

Also, one can easily define a procedural macro that automatically defines a map-like operation on such an enum, so you could write something like

#[define_map_operation]
enum AttrType<T> {
    Meta(T),
    Status(T),
    Content(T),
}

In fact, I could even find (more or less) such a proc macro in this crate, although.. it’s a derive macro for a Functor trait and using that whole crate if probably overkill for just using the map operation.

1 Like