Rust не имеет специальных конструкторов как, например, в C++/Java. Обычно конструктор реализуется как ассоциированная функция (например, new). Важные особенности:
::.Result<Self, E> — удобно для fallible-конструкторов.with_capacity, from_str, кастомные варианты).Пример базового конструктора:
struct Point { x: i32, y: i32 } impl Point { pub fn new(x: i32, y: i32) -> Self { Point { x, y } } }
Пример fallible конструктора:
impl Point { pub fn try_new(x: i32, y: i32) -> Result<Self, String> { if x < 0 || y < 0 { Err("Coordinates must be non-negative".to_string()) } else { Ok(Point { x, y }) } } }
Какой тип функции должен использоваться для конструктора: обычная функция, метод или ассоциированная функция, и почему?
Многие отвечают: "метод". Но в Rust конструкторы — только ассоциированные функции (без self), так как экземпляра ещё нет и вызвать обычный метод невозможно.
struct Foo; impl Foo { // ассоциированная функция, не метод pub fn new() -> Self { Foo } }
История
Программист реализовал конструктор как метод:
impl Point { pub fn make(&self, x: i32, y: i32) -> Self { ... } }Это нелогично и запутывает: для создания объекта нужен объект, который ещё не существует! Разработчик терялся, как вызывать этот метод. Исправили на статическую функцию.
История
Классическая ошибка: возвращать Option<Self> для fallible-конструктора без предупреждения, из-за чего пропуск каскадных ошибок. После того как вернули Result<Self, E>, стало возможно выводить ошибки более явно.
История
Реализация фабрик вида
from_parts,from_strбез использования trait’а From/FromStr. В результате не работали стандартные механизмы преобразований (например,str.parse::<MyType>()). После обнаружения ошибки внедрили FromStr и повысили совместимость кода с библиотеками экосистемы.