Почему ленивое-статическое значение утверждает, что не реализует черту, которую оно явно реализует?
С помощью следующего кода (попытка сделать 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(¶ms).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(¶ms).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);
Кроме того, использование пустой статической переменной будет пытаться переместить ее из статического местоположения (что было бы очень плохо), поэтому вам всегда нужно использовать ее по ссылке.