How to Implicitly Pass a Generic Type to an Associated Function

Hello,

Please I have a struct that has a field (called params) with a generic type
e.g

struct Request<T> {
    method: String,
    params: T,
    id: String,
}

And I have an enum called Method which determines the data type for params when I create a new Request.

enum Method {
    Init,
    Register,
}

And these are the types that can be assigned to params:

struct InitRequest;
struct Register;
...

Now, I want to implement an associated function called new that uses Method to determine the type for params. How can I implement Request::new so that the function can be called this way:

let req = Request::new(Method::Init);

Here is the implementation I want, but how do I make rust know the type for params?

impl<T> Request<T> {
    fn new(method: Method) -> Request {
        match method {
            Method::Init => {
                Request {method: String::from("init"),
                    params: InitRequest::new(),
                    id: String::from("xxx"),
                }
            },
            Method::Register => {
                Request {method: String::from("register"),
                    params: Register::new(),
                    id: String::from("xxx"),
                }
            }
        }
    }
}

How do I make Rust determine the type for params without passing it as an argument to Request::new(Method)?

I could have done something like this:

impl<T> Request<T> {
    fn new(params: T) -> Request<T> {
                Request {
                   method: String::from("init"),
                    params: params,
                    id: String::from("xxx"),
                }
}
...

But Id on't want to pass the generic type T as an argument to the associated function new.

Reference code: Rust Playground

Thanks

You can't use generics in this way. Consider using an enum to store the value instead?

1 Like

Thanks Alice for the feedback. Kindly expantiate what you mean.

You could use:

enum RequestParams {
    InitParams(InitParams),
    Register(RegisterParams),
}

If it's an HTTP request, you can probably just use strings for params, e.g. params: Vec<String> (or HashMap, etc.)

If you really need structs, then define

trait Method {
    type Params;
}
struct InitMethod;
impl Method for InitMethod {
    type Params = MethodParams;
}

fn new<M: Method>(method: M) -> Request<Method::Params>
1 Like

Thanks Kornel. I will try the traits option because the params field takes several complex structs.

The enum approach worked. Thanks Kornel and Alice.

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.