Search code examples
compiler-errorsrusthyper

Why do I get the error "wrong number of type arguments" when I use hyper::Client in my method signature?


I want to get a hyper::Client configured according to the URL scheme. For that, I created a small method:

extern crate http; // 0.1.8
extern crate hyper; // 0.12.7
extern crate hyper_tls; // 0.1.4

use http::uri::Scheme;
use hyper::{Body, Client, Uri};
use hyper_tls::HttpsConnector;

#[derive(Clone, Debug)]
pub struct Feed;

impl Feed {
    fn get_client(uri: Uri) -> Client {
        match uri.scheme_part() {
            Some(Scheme::HTTP) => Client::new(),
            Some(Scheme::HTTPS) => {
                let https = HttpsConnector::new(4).expect("TLS initialization failed");
                let client = Client::builder().build::<_, Body>(https);
            }
            _ => panic!("We don't support schemes other than HTTP/HTTPS"),
        }
    }
}

When I try to compile it, I get this error message:

error[E0243]: wrong number of type arguments: expected at least 1, found 0
  --> src/main.rs:13:32
   |
13 |     fn get_client(uri: Uri) -> Client {
   |                                ^^^^^^ expected at least 1 type argument

I don't understand why it doesn't compile since

  • I've declared my use of the hyper crate in my main.rs
  • I declare my use in file header

What am I doing wrong ?


Solution

  • Look at the documentation for Client: Client is a generic type which depends on two type parameters: a connector type C and an optional body type B. You would need to specify which type parameters apply to the Client that you return, except that in your specific case it looks like you want to return either a Client<HttpConnector> or a Client<HttpsConnector> depending on the URI scheme. You can't do that, period.

    Depending on how you intend to use your get_client function, you can wrap the return value in an enum:

    enum MyClient {
        HttpClient (Client<HttpConnector>),
        HttpsClient (Client<HttpsConnector>),
    }
    impl MyClient {
        pub fn get(&self, uri: Uri) -> ResponseFuture {
            match self {
                HttpClient (c) => c.get (uri),
                HttpsClient (c) => c.get (uri),
            }
        }
    }
    
    fn get_client(uri: Uri) -> MyClient { /* … */ }
    

    or you can define a trait, implement it for Client<HttpConnector> and Client<HttpsConnector> and have get_client return a boxed instance of your trait, something like:

    trait MyClient {
        pub fn get(&self, uri: Uri) -> ResponseFuture;
    }
    impl<C> MyClient for Client<C> {
        pub fn get(&self, uri: Uri) -> ResponseFuture {
            Client<C>::get (&self, uri)
        }
    }
    
    fn get_client(uri: Uri) -> Box<MyClient> { /* … */ }