Трейт 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 T
  • From рефлексивен, что означает, что 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>

Примитивные типы и числовые преобразования

Целевой типИсходный типОписание преобразования
booli8, i16, i32, i64, i128, u8, u16, u32, u64, u1280false, любое другое значение → true
f32i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f64Числовое преобразование с плавающей точкой
f64i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32Числовое преобразование с плавающей точкой
i8boolfalse0, true1
i16bool, i8, u8Числовое преобразование
i32bool, i8, u8, i16, u16, charЧисловое преобразование, char → Unicode scalar value
i64bool, i8, u8, i16, u16, i32, u32, charЧисловое преобразование
i128Все меньшие целые и bool, charЧисловое преобразование
u8bool, char (только значения 0-255)false0, true1, char → byte value
u16bool, u8, charЧисловое преобразование, char → Unicode scalar value
u32bool, u8, u16, charЧисловое преобразование, char → Unicode scalar value
u64bool, 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)

Сетевые типы

Целевой типИсходный типОписание преобразования
IpAddrIpv4Addr, Ipv6AddrКонкретный IP → общий IP адрес
SocketAddrSocketAddrV4, SocketAddrV6Конкретный socket → общий socket адрес

Системные типы

Целевой типИсходный типОписание преобразования
CStringVec<u8>, &[u8], &strСоздание C-совместимой строки
OsStringString, &strСоздание OS-специфичной строки
PathBufString, &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