|
1 | 1 | % Constructors
|
2 | 2 |
|
3 |
| -Unlike C++, Rust does not come with a slew of builtin |
4 |
| -kinds of constructor. There are no Copy, Default, Assignment, Move, or whatever constructors. |
5 |
| -This largely has to do with Rust's philosophy of being explicit. |
6 |
| - |
7 |
| -Move constructors are meaningless in Rust because we don't enable types to "care" about their |
8 |
| -location in memory. Every type must be ready for it to be blindly memcopied to somewhere else |
9 |
| -in memory. This means pure on-the-stack-but-still-movable intrusive linked lists are simply |
10 |
| -not happening in Rust (safely). |
11 |
| - |
12 |
| -Assignment and copy constructors similarly don't exist because move semantics are the *default* |
13 |
| -in rust. At most `x = y` just moves the bits of y into the x variable. Rust does provide two |
14 |
| -facilities for going back to C++'s copy-oriented semantics: `Copy` and `Clone`. Clone is our |
15 |
| -moral equivalent of a copy constructor, but it's never implicitly invoked. You have to explicitly |
16 |
| -call `clone` on an element you want to be cloned. Copy is a special case of Clone where the |
17 |
| -implementation is just "copy the bits". Copy types *are* implicitly |
18 |
| -cloned whenever they're moved, but because of the definition of Copy this just means *not* |
19 |
| -treating the old copy as uninitialized -- a no-op. |
20 |
| - |
21 |
| -While Rust provides a `Default` trait for specifying the moral equivalent of a default |
22 |
| -constructor, it's incredibly rare for this trait to be used. This is because variables |
23 |
| -[aren't implicitly initialized][uninit]. Default is basically only useful for generic |
24 |
| -programming. In concrete contexts, a type will provide a static `new` method for any |
25 |
| -kind of "default" constructor. This has no relation to `new` in other |
26 |
| -languages and has no special meaning. It's just a naming convention. |
| 3 | +There is exactly one way to create an instance of a user-defined type: name it, |
| 4 | +and initialize all its fields at once: |
| 5 | + |
| 6 | +```rust |
| 7 | +struct Foo { |
| 8 | + a: u8, |
| 9 | + b: u32, |
| 10 | + c: bool, |
| 11 | +} |
| 12 | + |
| 13 | +enum Bar { |
| 14 | + X(u32), |
| 15 | + Y(bool), |
| 16 | +} |
| 17 | + |
| 18 | +struct Empty; |
| 19 | + |
| 20 | +let foo = Foo { a: 0, b: 1, c: false }; |
| 21 | +let bar = Bar::X(0); |
| 22 | +let empty = Empty; |
| 23 | +``` |
| 24 | + |
| 25 | +That's it. Every other way you make an instance of a type is just calling a |
| 26 | +totally vanilla function that does some stuff and eventually bottoms out to The |
| 27 | +One True Constructor. |
| 28 | + |
| 29 | +Unlike C++, Rust does not come with a slew of built in kinds of constructor. |
| 30 | +There are no Copy, Default, Assignment, Move, or whatever constructors. The |
| 31 | +reasons for this are varied, but it largely boils down to Rust's philosophy |
| 32 | +of *being explicit*. |
| 33 | + |
| 34 | +Move constructors are meaningless in Rust because we don't enable types to |
| 35 | +"care" about their location in memory. Every type must be ready for it to be |
| 36 | +blindly memcopied to somewhere else in memory. This means pure on-the-stack-but- |
| 37 | +still-movable intrusive linked lists are simply not happening in Rust (safely). |
| 38 | + |
| 39 | +Assignment and copy constructors similarly don't exist because move semantics |
| 40 | +are the *only* semantics in Rust. At most `x = y` just moves the bits of y into the x |
| 41 | +variable. Rust *does* provide two facilities for providing C++'s copy-oriented |
| 42 | +semantics: `Copy` and `Clone`. Clone is our moral equivalent of a copy |
| 43 | +constructor, but it's never implicitly invoked. You have to explicitly call |
| 44 | +`clone` on an element you want to be cloned. Copy is a special case of Clone |
| 45 | +where the implementation is just "copy the bits". Copy types *are* implicitly |
| 46 | +cloned whenever they're moved, but because of the definition of Copy this just |
| 47 | +means *not* treating the old copy as uninitialized -- a no-op. |
| 48 | + |
| 49 | +While Rust provides a `Default` trait for specifying the moral equivalent of a |
| 50 | +default constructor, it's incredibly rare for this trait to be used. This is |
| 51 | +because variables [aren't implicitly initialized][uninit]. Default is basically |
| 52 | +only useful for generic programming. In concrete contexts, a type will provide a |
| 53 | +static `new` method for any kind of "default" constructor. This has no relation |
| 54 | +to `new` in other languages and has no special meaning. It's just a naming |
| 55 | +convention. |
0 commit comments