Исторически одним из принципов Rust было обеспечение безопасности типов и отсутствие неявных преобразований, приводящих к ошибкам исполнения. Но для удобства кода частичные автоматические преобразования реализуются через deref coercion и From/Into трейты, чтобы упростить работу с ссылками, умными указателями, а также позволить универсальные API.
Проблема появляется тогда, когда автоматические приведения могут вызвать путаницу, например, при передаче &String туда, где ожидается &str. Вызывается скрытый Deref::deref, и иногда возникают непредвиденные последствия (например, при изменении типа передаваемых параметров). Также есть вопрос прямого и явного кастинга через as.
Решение: Rust реализует строгие правила deref-coercion для smart pointer'ов (Box, Rc, Arc) и строк (&String к &str, &Vec к &slice) на уровне компилятора. Для явных преобразований предусмотрены трейты From, Into, TryFrom, TryInto, as для базовых кастов. Избегать ошибок помогает статическая типизация и ограничение неявных преобразований.
Пример кода:
fn print_text(text: &str) { println!("{}", text); } let s = String::from("Hello!"); print_text(&s); // s: String, &s: &String, автоприведение к &str
Ключевые особенности:
Работает ли deref coercion для собственных типов, если реализовать Deref вручную?
Да, если вы реализуете трейт Deref для своего типа, компилятор сможет автоматически преобразовать, например, вашу обёртку в целевой тип внутри сигнатуры функции, ожидающей соответствующую ссылку.
Может ли происходить deref coercion для значений, а не для ссылок?
Нет, автоматическое разыменование происходит только при передаче ссылок, и только когда тип реализует Deref.
Какие ограничения у приведения типов через as при работе с числами и enum?
as не гарантирует безопасность: преобразование между типами чисел может вызвать переполнение или потерю данных, а для enum приведёт к несемантичным значениям (например, к некорректному варианту enum).
Новичок пишет функцию, принимающую &String, и не может использовать &str напрямую, везде делает text.to_string() из строки. Это расточительно по памяти и производительности.
Плюсы:
Минусы:
Функция принимает аргумент типа &str, благодаря чему может быть вызвана с любым типом, поддерживающим разыменование или приведением: &str, &String, строковые литералы. Не требуется лишних аллокаций.
Плюсы:
Минусы: