Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Преобразования через Try

Фактическое раскрытие ? немного сложнее, чем показано ранее:

// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

expression?

работает так же, как

// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

match expression {
    Ok(value) => value,
    Err(err)  => return Err(From::from(err)),
}

Вызов From::from здесь означает, что мы пытаемся преобразовать тип ошибки в тип, возвращаемый функцией. Это упрощает инкапсуляцию ошибок в более высокоуровневые ошибки.

Пример

// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

use std::error::Error;
use std::io::Read;
use std::{fmt, fs, io};

#[derive(Debug)]
enum ReadUsernameError {
    IoError(io::Error),
    EmptyUsername,
}

impl From<io::Error> for ReadUsernameError {
    fn from(err: io::Error) -> Self {
        Self::IoError(err)
    }
}

fn read_username(path: &str) -> Result<String, ReadUsernameError> {
    let mut username = String::with_capacity(100);
    fs::File::open(path)?.read_to_string(&mut username)?;
    if username.is_empty() {
        return Err(ReadUsernameError::EmptyUsername);
    }
    Ok(username)
}

fn main() {
    //std::fs::write("config.dat", "").unwrap();
    let username = read_username("config.dat");
    println!("username or error: {username:?}");
}
This slide should take about 5 minutes.

Оператор ? должен возвращать значение, совместимое с возвращаемым типом функции. Для Result это значит, что типы ошибок должны быть совместимы. Функция, возвращающая Result<T, ErrorOuter>, может использовать ? на значении типа Result<U, ErrorInner> только если ErrorOuter и ErrorInner — один и тот же тип или если ErrorOuter реализует From<ErrorInner>.

Распространённая альтернатива реализации From — Result::map_err, особенно когда преобразование происходит только в одном месте.

Для Option такого требования совместимости нет. Функция, возвращающая Option<T>, может использовать оператор ? на Option<U> для произвольных типов T и U.

Функция, возвращающая Result, не может использовать ? на Option, и наоборот. Однако Option::ok_or превращает Option в Result, а Result::ok превращает Result в Option.