ProgrammingRust Developer / Backend Developer

What are constructors and factory methods in Rust (e.g., new, with_capacity), how to implement them correctly, and what mistakes do beginners encounter?

Pass interviews with Hintsage AI assistant

Answer.

Rust does not have special constructors like, for example, in C++/Java. Usually, a constructor is implemented as an associated function (e.g., new). Key features:

  • An associated function is not tied to traits or an object, it is called via ::.
  • It can return either self or Result<Self, E> — convenient for fallible constructors.
  • Different factories can be implemented (with_capacity, from_str, custom variants).

Example of a basic constructor:

struct Point { x: i32, y: i32 } impl Point { pub fn new(x: i32, y: i32) -> Self { Point { x, y } } }

Example of a fallible constructor:

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 }) } } }

Trick question.

What type of function should be used for a constructor: a regular function, a method, or an associated function, and why?

Many respond: "method". But in Rust, constructors are only associated functions (without self), since an instance does not exist yet and a regular method cannot be called.

struct Foo; impl Foo { // associated function, not a method pub fn new() -> Self { Foo } }

Examples of real mistakes due to lack of understanding of the subtleties of the topic.


Story

A programmer implemented a constructor as a method:

impl Point { pub fn make(&self, x: i32, y: i32) -> Self { ... } }

This is illogical and confusing: to create an object, an object that does not exist yet is needed! The developer was perplexed about how to call this method. It was corrected to a static function.


Story

A classic mistake: returning Option<Self> for a fallible constructor without a warning, resulting in missing cascading errors. After returning Result<Self, E>, it became possible to report errors more explicitly.


Story

Implementing factories like from_parts, from_str without using the trait From/FromStr. As a result, standard conversion mechanisms did not work (for example, str.parse::<MyType>()). After discovering the error, we implemented FromStr and improved code compatibility with ecosystem libraries.