ПрограммированиеRust разработчик / Backend разработчик

Что такое конструкторы и фабричные методы в Rust (например, new, with_capacity), как правильно их реализовывать, и какие ошибки встречаются у начинающих?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Rust не имеет специальных конструкторов как, например, в C++/Java. Обычно конструктор реализуется как ассоциированная функция (например, new). Важные особенности:

  • Ассоциированная функция не связана с трейтами или объектом, вызывается через ::.
  • Она может возвращать как self, так и 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 и повысили совместимость кода с библиотеками экосистемы.