Трейт From
#![allow(unused)] fn main() { pub trait From<T>: Sized { // Обязательный метод fn from(value: T) -> Self; } }
Используется для преобразований значение-в-значение с потреблением входного значения. Является обратным к Into.
Всегда следует предпочитать реализацию From вместо Into, потому что реализация From автоматически предоставляет реализацию Into благодаря обобщённой реализации в стандартной библиотеке.
Реализуйте Into только при работе с версиями до Rust 1.41 и преобразовании в тип за пределами текущего крейта. From не мог выполнять такие преобразования в более ранних версиях из-за правил сиротства Rust. Смотрите Into для получения более подробной информации.
Предпочитайте использование Into вместо From при указании трейт-границ для обобщённой функции, чтобы гарантировать, что типы, которые реализуют только Into, также могут быть использованы.
Трейт From также очень полезен при обработке ошибок. При создании функции, которая может завершиться неудачей, возвращаемый тип обычно имеет форму Result<T, E>. From упрощает обработку ошибок, позволяя функции возвращать единственный тип ошибки, который инкапсулирует несколько типов ошибок. Смотрите раздел "Примеры" и книгу для более подробной информации.
Примечание: Этот трейт не должен завершаться неудачей. Трейт From предназначен для безупречных преобразований. Если преобразование может завершиться неудачей или не является безупречным, используйте TryFrom.
Обобщённые реализации
From<T> for UподразумеваетInto<U> for TFromрефлексивен, что означает, чтоFrom<T> for Tреализован
Когда реализовывать From
Хотя нет технических ограничений на то, какие преобразования могут быть выполнены с помощью реализации From, общее ожидание заключается в том, что преобразования обычно должны быть ограничены следующим:
-
Преобразование безупречно: если преобразование может завершиться неудачей, используйте вместо этого
TryFrom; не предоставляйте реализациюFrom, которая паникует. -
Преобразование без потерь: семантически оно не должно терять или отбрасывать информацию. Например, существует
i32: From<u16>, где исходное значение может быть восстановлено с помощьюu16: TryFrom<i32>. И существуетString: From<&str>, где вы можете получить что-то эквивалентное исходному значению черезDeref. НоFromнельзя использовать для преобразования изu32вu16, поскольку это не может быть успешным без потерь. (Здесь есть некоторый простор для информации, которая не считается семантически значимой. Например, существуетBox<[T]>: From<Vec<T>>, даже если он может не сохранять ёмкость, подобно тому как два вектора могут быть равны, несмотря на разную ёмкость.) -
Преобразование сохраняет значение: концептуальный вид и значение результирующего значения одинаковы, даже если тип Rust и техническое представление могут отличаться. Например,
-1_i8 as u8выполняется без потерь, поскольку приведение обратно может восстановить исходное значение, но это преобразование недоступно черезFrom, потому что-1и255являются разными концептуальными значениями (несмотря на идентичные битовые шаблоны технически). Ноf32: From<i16>доступно, потому что1_i16и1.0_f32концептуально представляют одно и то же вещественное число (несмотря на очень разные битовые шаблоны технически).String: From<char>доступно, потому что оба представляют текст, ноString: From<u32>недоступно, поскольку1(число) и"1"(текст) слишком различны. (Преобразование значений в текст вместо этого покрывается трейтомDisplay.) -
Преобразование очевидно: это единственное разумное преобразование между двумя типами. В противном случае лучше иметь именованный метод или конструктор, как, например,
str::as_bytesявляется методом и как целые числа имеют методыu32::from_ne_bytes,u32::from_le_bytesиu32::from_be_bytes, ни один из которых не является реализациейFrom. В то же время существует только один разумный способ обернутьIpv6AddrвIpAddr, поэтому существуетIpAddr: From<Ipv6Addr>.
Примеры
String реализует From<&str>:
Явное преобразование из &str в String выполняется следующим образом:
#![allow(unused)] fn main() { let string = "hello".to_string(); let other_string = String::from("hello"); assert_eq!(string, other_string); }
При обработке ошибок часто полезно реализовать From для вашего собственного типа ошибки. Преобразуя базовые типы ошибок в наш собственный пользовательский тип ошибки, который инкапсулирует базовый тип ошибки, мы можем возвращать единственный тип ошибки без потери информации о базовой причине. Оператор ? автоматически преобразует базовый тип ошибки в наш пользовательский тип ошибки с помощью From::from.
#![allow(unused)] fn main() { use std::fs; use std::io; use std::num; enum CliError { IoError(io::Error), ParseError(num::ParseIntError), } impl From<io::Error> for CliError { fn from(error: io::Error) -> Self { CliError::IoError(error) } } impl From<num::ParseIntError> for CliError { fn from(error: num::ParseIntError) -> Self { CliError::ParseError(error) } } fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> { let mut contents = fs::read_to_string(&file_name)?; let num: i32 = contents.trim().parse()?; Ok(num) } }
Обязательные методы
1.0.0 · Source
#![allow(unused)] fn main() { fn from(value: T) -> Self }
Преобразует в этот тип из входного типа.
Совместимость с dyn
Этот трейт не совместим с dyn.
В более старых версиях Rust совместимость с dyn называлась "объектной безопасностью", поэтому этот трейт не является объектно-безопасным.
Сводная таблица реализаций трейта From<T>
Примитивные типы и числовые преобразования
| Целевой тип | Исходный тип | Описание преобразования |
|---|---|---|
bool | i8, i16, i32, i64, i128, u8, u16, u32, u64, u128 | 0 → false, любое другое значение → true |
f32 | i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f64 | Числовое преобразование с плавающей точкой |
f64 | i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32 | Числовое преобразование с плавающей точкой |
i8 | bool | false → 0, true → 1 |
i16 | bool, i8, u8 | Числовое преобразование |
i32 | bool, i8, u8, i16, u16, char | Числовое преобразование, char → Unicode scalar value |
i64 | bool, i8, u8, i16, u16, i32, u32, char | Числовое преобразование |
i128 | Все меньшие целые и bool, char | Числовое преобразование |
u8 | bool, char (только значения 0-255) | false → 0, true → 1, char → byte value |
u16 | bool, u8, char | Числовое преобразование, char → Unicode scalar value |
u32 | bool, u8, u16, char | Числовое преобразование, char → Unicode scalar value |
u64 | bool, u8, u16, u32, char | Числовое преобразование |
u128 | Все меньшие беззнаковые целые и bool, char | Числовое преобразование |
Строковые типы
| Целевой тип | Исходный тип | Описание преобразования |
|---|---|---|
String | &str, &mut str, char, Box<str> | Создание owned строки из различных строковых представлений |
Box<str> | String, &str, &mut str, Box<&str> | Создание boxed строкового среза |
Cow<'_, str> | String, &str, &mut str | Создание clone-on-write строки |
Arc<str> | String, &str | Создание атомарно подсчитываемой строки |
Rc<str> | String, &str | Создание подсчитываемой строки |
Коллекции и контейнеры
| Целевой тип | Исходный тип | Описание преобразования |
|---|---|---|
Vec<T> | VecDeque<T>, BinaryHeap<T>, LinkedList<T>, [T; N], Box<[T]> | Преобразование между коллекциями |
VecDeque<T> | Vec<T>, [T; N] | Создание двусторонней очереди |
BinaryHeap<T> | Vec<T> | Создание двоичной кучи |
LinkedList<T> | Vec<T> | Создание связного списка |
Box<[T]> | Vec<T>, [T; N], Box<[T; N]> | Создание boxed среза |
Vec<u8> | String | Строка → вектор байтов (UTF-8) |
Умные указатели и ссылки
| Целевой тип | Исходный тип | Описание преобразования |
|---|---|---|
Box<T> | T, Rc<T>, Arc<T>, Pin<P> | Создание boxed значения |
Rc<T> | Box<T>, Arc<T>, T | Создание подсчитываемой ссылки |
Arc<T> | Box<T>, Rc<T>, T | Создание атомарно подсчитываемой ссылки |
Pin<P> | P | Закрепление указателя |
&[T] | &[T; N] | Массив → срез |
&mut [T] | &mut [T; N] | Изменяемый массив → изменяемый срез |
&str | &String | Ссылка на String → строковый срез |
Option и Result
| Целевой тип | Исходный тип | Описание преобразования |
|---|---|---|
Option<T> | T (через Some) | Значение → Some(value) |
Result<T, E> | T (через Ok) | Значение → Ok(value) |
Сетевые типы
| Целевой тип | Исходный тип | Описание преобразования |
|---|---|---|
IpAddr | Ipv4Addr, Ipv6Addr | Конкретный IP → общий IP адрес |
SocketAddr | SocketAddrV4, SocketAddrV6 | Конкретный socket → общий socket адрес |
Системные типы
| Целевой тип | Исходный тип | Описание преобразования |
|---|---|---|
CString | Vec<u8>, &[u8], &str | Создание C-совместимой строки |
OsString | String, &str | Создание OS-специфичной строки |
PathBuf | String, &str, OsString | Создание пути файловой системы |
Специальные типы
| Целевой тип | Исходный тип | Описание преобразования |
|---|---|---|
NonNull<T> | &T, &mut T | Ссылка → ненулевой указатель |
Cell<T> | T | Значение → cell |
RefCell<T> | T | Значение → ref cell |
Mutex<T> | T | Значение → mutex guard |
RwLock<T> | T | Значение → rwlock |