@@ -18,6 +18,8 @@ x.foo().bar().baz();
18
18
Luckily, as you may have guessed with the leading question, you can! Rust provides
19
19
the ability to use this * method call syntax* via the ` impl ` keyword.
20
20
21
+ ## Method calls
22
+
21
23
Here's how it works:
22
24
23
25
``` {rust}
@@ -56,11 +58,56 @@ other parameter. Because we know it's a `Circle`, we can access the `radius`
56
58
just like we would with any other struct. An import of π and some
57
59
multiplications later, and we have our area.
58
60
61
+ ## Chaining method calls
62
+
63
+ So, now we know how to call a method, such as ` foo.bar() ` . But what about our
64
+ original example, ` foo.bar().baz() ` ? This is called 'method chaining', and we
65
+ can do it by returning ` self ` .
66
+
67
+ ```
68
+ struct Circle {
69
+ x: f64,
70
+ y: f64,
71
+ radius: f64,
72
+ }
73
+
74
+ impl Circle {
75
+ fn area(&self) -> f64 {
76
+ std::f64::consts::PI * (self.radius * self.radius)
77
+ }
78
+
79
+ fn grow(&self) -> Circle {
80
+ Circle { x: self.x, y: self.y, radius: (self.radius * 10.0) }
81
+ }
82
+ }
83
+
84
+ fn main() {
85
+ let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
86
+ println!("{}", c.area());
87
+
88
+ let d = c.grow().area();
89
+ println!("{}", d);
90
+ }
91
+ ```
92
+
93
+ Check the return type:
94
+
95
+ ```
96
+ # struct Circle;
97
+ # impl Circle {
98
+ fn grow(&self) -> Circle {
99
+ # Circle } }
100
+ ```
101
+
102
+ We just say we're returning a ` Circle ` . With this, we can grow a new circle
103
+ that's twice as big as the old one.
104
+
105
+ ## Static methods
106
+
59
107
You can also define methods that do not take a ` self ` parameter. Here's a
60
108
pattern that's very common in Rust code:
61
109
62
- ``` {rust}
63
- # #![allow(non_shorthand_field_patterns)]
110
+ ```
64
111
struct Circle {
65
112
x: f64,
66
113
y: f64,
@@ -86,3 +133,66 @@ This *static method* builds a new `Circle` for us. Note that static methods
86
133
are called with the ` Struct::method() ` syntax, rather than the ` ref.method() `
87
134
syntax.
88
135
136
+ ## Builder Pattern
137
+
138
+ Let's say that we want our users to be able to create Circles, but we will
139
+ allow them to only set the properties they care about. Otherwise, the ` x `
140
+ and ` y ` attributes will be ` 0.0 ` , and the ` radius ` will be ` 1.0 ` . Rust doesn't
141
+ have method overloading, named arguments, or variable arguments. We employ
142
+ the builder pattern instead. It looks like this:
143
+
144
+ ```
145
+ struct Circle {
146
+ x: f64,
147
+ y: f64,
148
+ radius: f64,
149
+ }
150
+
151
+ impl Circle {
152
+ fn area(&self) -> f64 {
153
+ std::f64::consts::PI * (self.radius * self.radius)
154
+ }
155
+ }
156
+
157
+ struct CircleBuilder {
158
+ coordinate: f64,
159
+ radius: f64,
160
+ }
161
+
162
+ impl CircleBuilder {
163
+ fn new() -> CircleBuilder {
164
+ CircleBuilder { coordinate: 0.0, radius: 0.0, }
165
+ }
166
+
167
+ fn coordinate(&mut self, coordinate: f64) -> &mut CircleBuilder {
168
+ self.coordinate = coordinate;
169
+ self
170
+ }
171
+
172
+ fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
173
+ self.radius = radius;
174
+ self
175
+ }
176
+
177
+ fn finalize(&self) -> Circle {
178
+ Circle { x: self.coordinate, y: self.coordinate, radius: self.radius }
179
+ }
180
+ }
181
+
182
+ fn main() {
183
+ let c = CircleBuilder::new()
184
+ .coordinate(10.0)
185
+ .radius(5.0)
186
+ .finalize();
187
+
188
+
189
+ println!("area: {}", c.area());
190
+ }
191
+ ```
192
+
193
+ What we've done here is make another struct, ` CircleBuilder ` . We've defined our
194
+ builder methods on it. We've also defined our ` area() ` method on ` Circle ` . We
195
+ also made one more method on ` CircleBuilder ` : ` finalize() ` . This method creates
196
+ our final ` Circle ` from the builder. Now, we've used the type system to enforce
197
+ our concerns: we can use the methods on ` CircleBuilder ` to constrain making
198
+ ` Circle ` s in any way we choose.
0 commit comments