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:
::.Result<Self, E> — convenient for fallible constructors.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 }) } } }
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 } }
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_strwithout 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.