Почему ленивое-статическое значение утверждает, что не реализует черту, которую оно явно реализует?

С помощью следующего кода (попытка сделать HTTP-запрос с использованием reqwest crate), компилятор говорит, что моя ценность SID_URI не реализует черту PolyfillTryInto, Что тут происходит? reqwest::Url четко реализует частную черту 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 ответ

Решение

Компилятор не обманывает вас, вы просто пропускаете соответствующую деталь сообщения об ошибке. Вот отдельный пример:

#[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`

Сравните два сообщения об ошибках:

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

Второе сообщение об ошибке не говорит, что 42 не реализует ExampleTrait это говорит о том, что i32 не хватает реализации. Это сообщение об ошибке показывает тип ошибки, а не имя значения! Это означает, что EXAMPLE в том же контексте относится к типу.

Lazy-static работает путем создания одноразовых типов, которые обертывают ваше значение и обеспечивают поточную безопасную единственную гарантию инициализации:

Для данного static ref NAME: TYPE = EXPR;, макрос генерирует уникальный тип, который реализует Deref<TYPE> и хранит его в статике с именем NAME,

Этот тип обертки не реализует вашу черту, только обернутый тип делает. Вам нужно будет призвать Deref а затем, вероятно, повторно ссылаться на него, чтобы добраться до &Url, предполагая, что ссылка на Url реализует вашу черту:

must_have_trait(&*EXAMPLE);

Кроме того, использование пустой статической переменной будет пытаться переместить ее из статического местоположения (что было бы очень плохо), поэтому вам всегда нужно использовать ее по ссылке.

Другие вопросы по тегам