Трейт TryFrom
#![allow(unused)] fn main() { pub trait TryFrom<T>: Sized { type Error; // Обязательный метод fn try_from(value: T) -> Result<Self, Self::Error>; } }
Простые и безопасные преобразования типов, которые могут завершиться неудачей контролируемым образом в некоторых обстоятельствах. Является обратным к TryInto.
Это полезно, когда вы выполняете преобразование типа, которое может тривиально завершиться успехом, но также может потребовать специальной обработки. Например, нет способа преобразовать i64 в i32 с помощью трейта From, потому что i64 может содержать значение, которое i32 не может представить, и поэтому преобразование приведёт к потере данных. Это можно обработать путём усечения i64 до i32, простого возврата i32::MAX или каким-либо другим методом. Трейт From предназначен для безупречных преобразований, поэтому трейт TryFrom информирует программиста, когда преобразование типа может пойти плохо, и позволяет ему решить, как с этим справиться.
Обобщённые реализации
TryFrom<T> for UподразумеваетTryInto<U> for Ttry_fromрефлексивен, что означает, чтоTryFrom<T> for Tреализован и не может завершиться неудачей - связанный типErrorдля вызоваT::try_from()на значении типаTявляетсяInfallible. Когда тип!стабилизируется,Infallibleи!будут эквивалентны.
Предпочитайте использование TryInto вместо TryFrom при указании трейт-границ для обобщённой функции, чтобы гарантировать, что типы, которые реализуют только TryInto, также могут быть использованы.
TryFrom<T> может быть реализован следующим образом:
#![allow(unused)] fn main() { struct GreaterThanZero(i32); impl TryFrom<i32> for GreaterThanZero { type Error = &'static str; fn try_from(value: i32) -> Result<Self, Self::Error> { if value <= 0 { Err("GreaterThanZero only accepts values greater than zero!") } else { Ok(GreaterThanZero(value)) } } } }
Примеры
Как описано, i32 реализует TryFrom<i64>:
#![allow(unused)] fn main() { let big_number = 1_000_000_000_000i64; // Тихо усекает `big_number`, требует обнаружения // и обработки усечения после факта. let smaller_number = big_number as i32; assert_eq!(smaller_number, -727379968); // Возвращает ошибку, потому что `big_number` слишком велик, // чтобы поместиться в `i32`. let try_smaller_number = i32::try_from(big_number); assert!(try_smaller_number.is_err()); // Возвращает `Ok(3)`. let try_successful_smaller_number = i32::try_from(3); assert!(try_successful_smaller_number.is_ok()); }
Обязательные связанные типы
1.34.0 · Source
#![allow(unused)] fn main() { type Error }
Тип, возвращаемый в случае ошибки преобразования.
Обязательные методы
1.34.0 · Source
#![allow(unused)] fn main() { fn try_from(value: T) -> Result<Self, Self::Error> }
Выполняет преобразование.
Совместимость с dyn
Этот трейт не совместим с dyn.
В более старых версиях Rust совместимость с dyn называлась "объектной безопасностью", поэтому этот трейт не является объектно-безопасным.
Реализаторы
Сводная таблица реализаций трейта TryFrom<T>
| Целевой тип | Исходный тип | Тип ошибки | Условия успешного преобразования |
|---|---|---|---|
i8 | i16, i32, i64, i128, isize | TryFromIntError | Значение в пределах i8::MIN..=i8::MAX |
i16 | i32, i64, i128, isize | TryFromIntError | Значение в пределах i16::MIN..=i16::MAX |
i32 | i64, i128, isize | TryFromIntError | Значение в пределах i32::MIN..=i32::MAX |
i64 | i128 | TryFromIntError | Значение в пределах i64::MIN..=i64::MAX |
u8 | i8, i16, i32, i64, i128, isize, u16, u32, u64, u128, usize | TryFromIntError | Для знаковых: значение ≥ 0 и ≤ u8::MAXДля беззнаковых: значение ≤ u8::MAX |
u16 | i16, i32, i64, i128, isize, u32, u64, u128, usize | TryFromIntError | Для знаковых: значение ≥ 0 и ≤ u16::MAXДля беззнаковых: значение ≤ u16::MAX |
u32 | i32, i64, i128, isize, u64, u128, usize | TryFromIntError | Для знаковых: значение ≥ 0 и ≤ u32::MAXДля беззнаковых: значение ≤ u32::MAX |
u64 | i64, i128, u128 | TryFromIntError | Для знаковых: значение ≥ 0 и ≤ u64::MAXДля беззнаковых: значение ≤ u64::MAX |
usize | i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128 | TryFromIntError | Зависит от архитектуры платформы |
isize | i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize | TryFromIntError | Зависит от архитектуры платформы |
char | u8 | CharTryFromError | Значение в пределах 0..=0x7F (валидный ASCII) |
CString | Vec<u8> | FromVecWithNulError | Вектор не содержит нулевых байтов |
OsString | PathBuf | (нет ошибки) | Всегда успешно |
PathBuf | OsString | (нет ошибки) | Всегда успешно |
String | &str | (нет ошибки) | Всегда успешно |
Vec<T> | VecDeque<T>, BinaryHeap<T>, LinkedList<T>, Box<[T]> | (нет ошибки) | Всегда успешно |
Дополнительные реализации для примитивных типов
Преобразования между целыми числами
- Все комбинации между знаковыми и беззнаковыми целыми
- Проверка на переполнение и отрицательные значения
- Возвращает
TryFromIntErrorпри нарушении границ
Строковые преобразования
#![allow(unused)] fn main() { // char из u8 (только ASCII) let ascii_char = char::try_from(65u8).unwrap(); // 'A' let invalid_char = char::try_from(255u8); // Err(CharTryFromError) // CString из Vec<u8> let valid_vec = vec![b'h', b'i']; let cstring = CString::try_from(valid_vec).unwrap(); let invalid_vec = vec![0, 1, 2]; let error = CString::try_from(invalid_vec); // Err(FromVecWithNulError) }
Особенности обработки ошибок
TryFromIntError
- Для всех числовых преобразований между целыми типами
- Не содержит дополнительной информации о причине ошибки
- Реализует
Debug,Display,Error
CharTryFromError
- Специфична для преобразований в
char - Возникает при невалидных значениях Unicode
FromVecWithNulError
- Для преобразований в
CString - Возникает при наличии нулевых байтов в векторе
- Предоставляет метод
into_bytes()для восстановления исходных данных