Why does a lazy-static value claim to not implement a trait that it clearly implements?

ぃ、小莉子 提交于 2019-11-27 07:06:30

问题


With the following code (an attempt to make an HTTP request using the reqwest crate), the compiler says that my value SID_URI does not implement the trait PolyfillTryInto. What's going on here? reqwest::Url clearly implements the private trait reqwest::into_url::PolyfillTryInto.

#[macro_use]
extern crate lazy_static;
extern crate reqwest;

static R_EMAIL: &str = "example@example.com";
static R_PASS: &str = "password";
static API_PUBKEY: &str = "99754106633f94d350db34d548d6091a";
static API_URI: &str = "https://example.com";
static AUTH_PATH: &str = "/api/v1";

lazy_static! {
    static ref SID_URI: reqwest::Url = reqwest::Url::parse(&(API_URI.to_owned() + AUTH_PATH)).unwrap();
}

fn get_sid() -> Result<reqwest::Response, reqwest::Error> {
    let client = reqwest::Client::new();
    let params = [("ID", R_EMAIL), ("PW", R_PASS), ("KY", API_PUBKEY)];
    let q = client.post(SID_URI).form(&params).send()?;
    Ok(q)
}

fn main() {
    assert!(get_sid().is_ok());
}
error[E0277]: the trait bound `SID_URI: reqwest::into_url::PolyfillTryInto` is not satisfied
  --> src/main.rs:19:20
   |
19 |     let q = client.post(SID_URI).form(&params).send()?;
   |                    ^^^^ the trait `reqwest::into_url::PolyfillTryInto` is not implemented for `SID_URI`
   |
   = note: required because of the requirements on the impl of `reqwest::IntoUrl` for `SID_URI`

回答1:


The compiler isn't lying to you, you are just skipping over a relevant detail of the error message. Here's a self-contained example:

#[macro_use]
extern crate lazy_static;

struct Example;
trait ExampleTrait {}
impl ExampleTrait for Example {}

lazy_static! {
    static ref EXAMPLE: Example = Example;
}

fn must_have_trait<T>(_: T)
where
    T: ExampleTrait,
{
}

fn main() {
    must_have_trait(EXAMPLE);
    must_have_trait(42i32);
}
error[E0277]: the trait bound `EXAMPLE: ExampleTrait` is not satisfied
  --> src/main.rs:19:5
   |
19 |     must_have_trait(EXAMPLE);
   |     ^^^^^^^^^^^^^^^ the trait `ExampleTrait` is not implemented for `EXAMPLE`
   |
   = note: required by `must_have_trait`

error[E0277]: the trait bound `i32: ExampleTrait` is not satisfied
  --> src/main.rs:20:9
   |
20 |         must_have_trait(42i32);
   |         ^^^^^^^^^^^^^^^ the trait `ExampleTrait` is not implemented for `i32`
   |
   = note: required by `must_have_trait`

Compare the two error messages:

the trait bound `EXAMPLE: ExampleTrait` is not satisfied
the trait bound `i32: ExampleTrait` is not satisfied

The second error message doesn't say that 42 does not implement ExampleTrait, it says that i32 lacks the implementation. This error message shows the type that fails, not the name of the value! That means that EXAMPLE in the same context is referring to a type.

Lazy-static works by creating one-off types that wrap your value and provide thread-safe single initialization guarantees:

For a given static ref NAME: TYPE = EXPR;, the macro generates a unique type that implements Deref<TYPE> and stores it in a static with name NAME.

This wrapper type does not implement your trait, only the wrapped type does. You will need to invoke Deref and then probably re-reference it to get to a &Url, assuming that a reference to a Url implements your trait:

must_have_trait(&*EXAMPLE);

Additionally, using the bare static variable would attempt to move it out of the static location (which would be a Very Bad Thing), so you always need to use it by reference.



来源:https://stackoverflow.com/questions/48114390/why-does-a-lazy-static-value-claim-to-not-implement-a-trait-that-it-clearly-impl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!