Generic type in a function (first timer)

Hi all,

I've got this:

pub async fn get<T>(config: &Config, debug: &u8, auth_for: bool, request_url: &str, json_type: T) -> String {
    if debug > &0 {
        println!("Getting: {}", request_url);
    }

    let client = Client::new();
    let resp = client
        .get(request_url)
        .headers(requests::headers(config, auth_for))
        .send()
        .await
        .expect("Failed to send requests");

    match resp.status() {
        reqwest::StatusCode::OK => match resp.json::<json_type>().await {

and getting:

attempt to use a non-constant value in a constant [E0435]

for

resp.json::<json_type>().await {

I have various Structs I'd like to convert the JSON responses to. What options do I have other than switching to:

resp.json::<serde_json::Value>().await

or hardcoding my Structs in there?

Basically this bit - Response in reqwest - Rust

Thanks.

You want to tell json() to use a specific type, but json_type isn't a type, it's a value of type T. T is the type variable that you want to pass to json().

... match resp.json::<T>().await {

Then you can probably remove the json_type: T parameter from the function. <T> is itself the declaration of the type parameter.

4 Likes

Ah, understood! I could't work that out from the examples at Generic Data Types - The Rust Programming Language nor have I used Generics in any other languages in anger.

Thanks and much appreciated @kpreid

When removing the function param, I actually want to pass something like ExtensionList:

to use to deserialize the JSON.

You pass that as a type parameter when calling the function, just like you did for json():

let result = get::<ExtensionList>(config, debug, auth_for, request_url).await;

Sometimes type parameters can be inferred from the usage, but in this case your function doesn't return T, it returns String, so that isn't happening here. If your function returned T then it'd be nicer to write:

let result: ExtensionList = get(config, debug, auth_for, request_url).await;
2 Likes

Thanks again!

Yep, I see that now:

If I returned T, how would I handle the String return types?

Well, you didn't show the rest of your function's code, but most of the time, I would expect that a function that makes a HTTP request, and is generic over the type to be deserialized from the HTTP response, is going to return (all or part of) the deserialized data. Perhaps you're doing something else, where returning a String instead makes sense.

I only intended to point out that it isn't the case that a generic function always needs its type parameters specified explicitly.

1 Like

The code lacking a generic type parameter is here :slight_smile:

Ah, I see. Then it makes sense that you are not using T in either the arguments or the return type.

By the way, debug: &u8 could be improved by making it debug: u8 instead; passing an & reference to an integer (or other small Copy type) is almost never better in any way than passing the integer itself. So, remove the & here and also in the calls to get(), and the program will be simpler.

(References to integers do unavoidably happen in certain situations with pattern matching, iterating, or generic code, but the best thing to do with those is to dereference them as soon as possible.)

3 Likes

Thanks again @kpreid

This was bugging me too and smelt funny:

    if debug > &0 {
        println!("Getting: {}", request_url);
    }