Диспетчеризация на основе возвращаемого типа
Перевод | Автор оригинала: Pascal Hertleif
Одна удивительная особенность вывода типов в таких языках, как Rust, - это определение функций с универсальными типами возврата. Идея состоит в том, что, указав на более позднем этапе кода, какой тип вы хотите, чтобы функция возвращала, компилятор может вернуться и заполнить пробелы.
Например, давайте посмотрим на эту функцию:
fn new<T: Default>() -> T {
T::default()
}
Вы выбираете выход
У него нет параметров значения, но есть один параметр типа T. Этот тип T является его возвращаемым типом и также используется в теле функции. Назвать это можно так:
let x: u32 = new();
Или, если явно указать параметр типа, например:
let x = new::<i32>();
Это довольно здорово!
Более общий: сбор
Многообещающий способ сделать Rust более универсальным - использовать больше трейтов! Посмотрите, как определяется метод Iterator::collect:
fn collect<B: FromIterator<Self::Item>>(self) -> B // ...
Вы можете прочитать эту подпись типа как
Потребляйте self и возвращайте что-то типа, который реализует, может быть сделан From [an] Iterator для типа элементов, которые мы повторяем.
Как и выше, мы вызываем это, указывая, какой тип вывода нужен. [Взгляд] [разработчиков FromIterator] на некоторые из типов, для которых реализован FromIterator, довольно показывает варианты использования. Вы можете получить:
- Vec, собирая любые предметы,
- BTreeMap или HashMap путем сбора кортежей,
- но также и PathBuf, собирая пути,
- и String для струн и фрагментов струн.
Все эти типы можно назвать «контейнерными».
Еще один в дорогу
Более общий? Больше черт.
В FromIterator спрятан еще один драгоценный камень:
impl<A, E, V> FromIterator<Result<A, E>> for Result<V, E> where
V: FromIterator<A>, // ...
Это означает: вы можете создать Result, содержащий любой тип контейнера элементов A, собирая элементы, которые являются Результатами типа A. (Первая ошибка сделает внешний Результат ошибкой.) Вот пример, см. Документацию для другого.
let input: Vec<Result<i32,()>> = vec![Ok(1), Ok(2)];
let output: Result<Vec<i32>,()> = input.into_iter().collect();
Если вам нравится теория типов: мы создаем Result<< T , E >>, собирая Result<A, E> и указывая T.
Спасибо за чтение.