Почему для сопоставления результата требуется явная ошибка при изменении типа результата? - PullRequest
0 голосов
/ 28 июня 2018

У меня есть выражение соответствия, от которого я хотел бы потенциально вернуть ошибку. Кажется, что компилятор не может сделать вывод, что последний случай e является Err(String) и требует, чтобы шаблон был явным:

fn foo() -> Result<Option<u8>, String> {
    unimplemented!() // don't mind the panic here
}

fn foo2() -> Result<u8, String> {
    let bar = foo();

    for _ in 0..3 {
        let baz = match bar {
            Ok(Some(b)) => b,
            Ok(None)    => continue,
            Err(e)      => return Err(e) // works
//          e           => return e      // error[E0308]
        };
    }

    Ok(0)
}

fn main() {
    let _ = foo2();
}

Ошибка:

error[E0308]: mismatched types
  --> src/main.rs:13:33
   |
13 |           e           => return e      // error[E0308]
   |                                 ^ expected u8, found enum `std::option::Option`
   |
   = note: expected type `std::result::Result<u8, _>`
              found type `std::result::Result<std::option::Option<u8>, _>`

Я почти уверен, что исчерпал все варианты Ok(_), поэтому осталось только Err(_). Эта ошибка не возникает, если, например, foo() возвращает Result<u8, String>. Я что-то упустил?

Ответы [ 3 ]

0 голосов
/ 28 июня 2018

Потому что Err не тип.

Err - это вариант Result<T, E>, тип которого Result<T, E>. Поскольку Result<T, E> отличается от Result<U, E>, кроме случаев T == U, и поскольку неявное преобразование не требуется, вам необходимо явно выполнить преобразование.

Я признаю, что это выглядит глупо, так как вывод типа заботится о выводе T, U и E в этом случае, что приводит к Err(e) => return Err(e), но на семантическом уровне эти 2 Err(e) имеют разные типы.

Для другого глупого примера:

enum Term<'a> {
    Int(i64),
    String(&'a str),
}

fn staticify(t: Term) -> Term<'static> {
    use Term::*;

    match t {
        String(_) => String("Hello, World!"),
        _ => t,
    }
}

Сбой по той же причине, потому что Term<'a> и Term<'static> не относятся к одному и тому же типу, если 'a == 'static. Когда Term содержит в основном не-временные параметры, это становится утомительным: (

0 голосов
/ 28 июня 2018

Вещи будут яснее, если вы используете квалифицированные типы для вашего Err(e) => return Err(e) случая. То, что вы действительно говорите здесь:

Result<Option<u8>, String>::Err(e) => return Result<u8, String>::Err(e)

Когда написано так, становится ясно, что происходит преобразование. И наоборот, e => return e эквивалентно:

Result<Option<u8>, String>::Err(e) => return Result<Option<u8>, String>::Err(e)

имеет неправильный тип, поскольку ваша функция должна возвращать Result<u8, String>.

0 голосов
/ 28 июня 2018

Вы соответствуете Result<Option<u8>, String>, поэтому e относится к этому типу, но ваша функция требует, чтобы возвращаемое значение было типа Result<u8, String>:

note: expected type `std::result::Result<u8, _>`
         found type `std::result::Result<std::option::Option<u8>, _>`
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...