rustrust-cargo

How can I use enum variants as generic type?


I want to use enum as type variant over a generic struct.

This gives me a error:

#[derive(Debug)]
enum Role {
    User,
    Admin,
}

#[derive(Debug)]
struct Session<T> {
    id: i64,
    role: T,
}

fn only_for_user(s: Session<Role::User>) {
    println!("{:?}", s);
}

fn only_for_admin(s: Session<Role::Admin>) {
    println!("{:?}", s);
}

fn main() {
    let session = Session {
        id: 1,
        role: Role::User,
    };
    only_for_user(session);
}
error[E0573]: expected type, found variant `Role::User`
  --> src/main.rs:13:29
   |
13 | fn only_for_user(s: Session<Role::User>) {
   |                             ^^^^^^^^^^
   |                             |
   |                             not a type
   |                             help: try using the variant's enum: `crate::Role`

error[E0573]: expected type, found variant `Role::Admin`
  --> src/main.rs:17:30
   |
17 | fn only_for_admin(s: Session<Role::Admin>) {
   |                              ^^^^^^^^^^^
   |                              |
   |                              not a type
   |                              help: try using the variant's enum: `crate::Role`

Playground.


Solution

  • You cannot do that. Enum variants are not types themselves (there was an RFC for that, however it was postponed).

    The usual way to do such thing is to have a struct that contains the variant data and to make the variant contain this struct:

    #[derive(Debug)]
    struct User;
    #[derive(Debug)]
    struct Admin;
    
    #[derive(Debug)]
    enum Role {
        User(User),
        Admin(Admin),
    }
    
    #[derive(Debug)]
    struct Session<T> {
        id: i64,
        role: T,
    }
    
    fn only_for_user(s: Session<User>) {
        println!("{:?}", s);
    }
    
    fn only_for_admin(s: Session<Admin>) {
        println!("{:?}", s);
    }
    
    fn main() {
        let session = Session {
            id: 1,
            role: User,
        };
        only_for_user(session);
    }
    

    You can tie the enum and the structs together with traits.