Почему выражение простого совпадения компилируется, а вызов map_err - нет? - PullRequest
0 голосов
/ 01 декабря 2018

Использование rustc 1.30.1 и reqwest 0.9.5.

У меня есть функция, которая вызывает несколько других функций, которые могут возвращать различные типы ошибок, в частности std::io::Error и reqwest::Error.

Чтобы передать их вызывающей стороне, простейшим решением, похоже, было бы поместить их в Box, который удобно реализует черту From<Error>, а также саму черту Error.Например:

fn fetch_input() -> Result<String, Box<dyn Error>> {
    ...
    let session_cookie = load_session_cookie()?; // Returns Result<String, io::Error>
    let text: Result<String, reqwest::Error> = ...;
    text.map_err(Box::new) // Compile error on this line
}

Однако этот код не компилируется:

error[E0308]: mismatched types                                                               
  --> src/main.rs:26:5                                                                       
   |                                                                                         
16 | fn fetch_input() -> Result<String, Box<dyn Error>> {                 
   |                     ------------------------------ expected `std::result::Result<std::string::String, std::boxed::Box<(dyn std::error::Error + 'static)>>` because of return type
...                                                                                          
26 |     text.map_err(Box::new)                                                              
   |     ^^^^^^^^^^^^^^^^^^^^^^ expected trait std::error::Error, found struct `reqwest::Error`
   |                                                                                         
   = note: expected type `std::result::Result<_, std::boxed::Box<(dyn std::error::Error + 'static)>>`
              found type `std::result::Result<_, std::boxed::Box<reqwest::Error>>`           

Если я заменю вызов map_err простым старым выражением match, все в порядке:

    match text {
        Ok(t) => Ok(t),
        Err(e) => Err(Box::new(e)),
    }

Обратите внимание, что это идентично телу реализации map_err в стандартной библиотеке.Так почему мой map_err вызов не проходит проверку типов?Само собой разумеется, reqwest::Error реализует черту std::error::Error .

. Мне также интересно, откуда берется время жизни 'static в сообщении об ошибке.Если это окажется не связанным, я мог бы открыть для него другой вопрос.

1 Ответ

0 голосов
/ 01 декабря 2018

Box::new делает одно, а только одно: берет reqwest::Error и помещает его в Box<reqwest::Error>.

выражение Box::new(e) выполняет две вещи: вызывает Box::new, который берет reqwest::Error и помещает его в Box<reqwest::Error>, , а затем он приводит Box<reqwest::Error> в Box<dyn Error>.

Типы принуждения - это то, чего обычно пытается избежать Rust.Box<T>Box<dyn Trait> (и другие подобные, прямой указатель → приведение указателя) является исключением.В частности, Rust не будет принуждать Result<T, Box<Err>> к Result<T, Box<dyn Error>>.

Что касается вас в стороне: потому что dyn Trait всегда требует соответствующего срока службы.Когда вы помещаете dyn Trait в коробку, это подразумевается как 'static.Если у вас есть &'a dyn Trait, предполагается, что он равен 'a.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...