Несколько типов ошибок

Предыдущие примеры всегда были очень удобны: Result взаимодействовали с другими Result, а Option - с другими Option.

Иногда Option необходимо взаимодействовать с Result, или Result<T, Error1> с Result<T, Error2>. В этих случаях, нам нужно управлять этими разными типами ошибок таким образом, чтобы можно было их компоновать и легко взаимодействовать с ними.

В следующем коде, два варианта unwrap генерируют разные типы ошибок. Vec::first возвращает Option, в то время как parse::<i32> возвращает Result<i32, ParseIntError>:

fn double_first(vec: Vec<&str>) -> i32 {
    let first = vec.first().unwrap(); // Генерирует ошибку 1
    2 * first.parse::<i32>().unwrap() // Генерирует ошибку 2
}

fn main() {
    let numbers = vec!["42", "93", "18"];
    let empty = vec![];
    let strings = vec!["tofu", "93", "18"];

    println!("Первое удвоенное {}", double_first(numbers));

    println!("Первое удвоенное {}", double_first(empty));
    // Ошибка 1: входной вектор пустой

    println!("Первое удвоенное {}", double_first(strings));
    // Ошибка 2: элемент не может быть преобразован в число
}

В следующих главах мы рассмотрим различные стратегии обработки этих типов проблем.