]> git.proxmox.com Git - rustc.git/blob - src/doc/book/method-syntax.md
b2532663339ff26aa1d7d6103b64359ddf25270e
[rustc.git] / src / doc / book / method-syntax.md
1 % Method Syntax
2
3 Functions are great, but if you want to call a bunch of them on some data, it
4 can be awkward. Consider this code:
5
6 ```rust,ignore
7 baz(bar(foo));
8 ```
9
10 We would read this left-to-right, and so we see ‘baz bar foo’. But this isn’t the
11 order that the functions would get called in, that’s inside-out: ‘foo bar baz’.
12 Wouldn’t it be nice if we could do this instead?
13
14 ```rust,ignore
15 foo.bar().baz();
16 ```
17
18 Luckily, as you may have guessed with the leading question, you can! Rust provides
19 the ability to use this ‘method call syntax’ via the `impl` keyword.
20
21 # Method calls
22
23 Here’s how it works:
24
25 ```rust
26 struct Circle {
27 x: f64,
28 y: f64,
29 radius: f64,
30 }
31
32 impl Circle {
33 fn area(&self) -> f64 {
34 std::f64::consts::PI * (self.radius * self.radius)
35 }
36 }
37
38 fn main() {
39 let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
40 println!("{}", c.area());
41 }
42 ```
43
44 This will print `12.566371`.
45
46 We’ve made a `struct` that represents a circle. We then write an `impl` block,
47 and inside it, define a method, `area`.
48
49 Methods take a special first parameter, of which there are three variants:
50 `self`, `&self`, and `&mut self`. You can think of this first parameter as
51 being the `foo` in `foo.bar()`. The three variants correspond to the three
52 kinds of things `foo` could be: `self` if it’s a value on the stack,
53 `&self` if it’s a reference, and `&mut self` if it’s a mutable reference.
54 Because we took the `&self` parameter to `area`, we can use it like any
55 other parameter. Because we know it’s a `Circle`, we can access the `radius`
56 like we would with any other `struct`.
57
58 We should default to using `&self`, as you should prefer borrowing over taking
59 ownership, as well as taking immutable references over mutable ones. Here’s an
60 example of all three variants:
61
62 ```rust
63 struct Circle {
64 x: f64,
65 y: f64,
66 radius: f64,
67 }
68
69 impl Circle {
70 fn reference(&self) {
71 println!("taking self by reference!");
72 }
73
74 fn mutable_reference(&mut self) {
75 println!("taking self by mutable reference!");
76 }
77
78 fn takes_ownership(self) {
79 println!("taking ownership of self!");
80 }
81 }
82 ```
83
84 You can use as many `impl` blocks as you’d like. The previous example could
85 have also been written like this:
86
87 ```rust
88 struct Circle {
89 x: f64,
90 y: f64,
91 radius: f64,
92 }
93
94 impl Circle {
95 fn reference(&self) {
96 println!("taking self by reference!");
97 }
98 }
99
100 impl Circle {
101 fn mutable_reference(&mut self) {
102 println!("taking self by mutable reference!");
103 }
104 }
105
106 impl Circle {
107 fn takes_ownership(self) {
108 println!("taking ownership of self!");
109 }
110 }
111 ```
112
113 # Chaining method calls
114
115 So, now we know how to call a method, such as `foo.bar()`. But what about our
116 original example, `foo.bar().baz()`? This is called ‘method chaining’. Let’s
117 look at an example:
118
119 ```rust
120 struct Circle {
121 x: f64,
122 y: f64,
123 radius: f64,
124 }
125
126 impl Circle {
127 fn area(&self) -> f64 {
128 std::f64::consts::PI * (self.radius * self.radius)
129 }
130
131 fn grow(&self, increment: f64) -> Circle {
132 Circle { x: self.x, y: self.y, radius: self.radius + increment }
133 }
134 }
135
136 fn main() {
137 let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
138 println!("{}", c.area());
139
140 let d = c.grow(2.0).area();
141 println!("{}", d);
142 }
143 ```
144
145 Check the return type:
146
147 ```rust
148 # struct Circle;
149 # impl Circle {
150 fn grow(&self, increment: f64) -> Circle {
151 # Circle } }
152 ```
153
154 We say we’re returning a `Circle`. With this method, we can grow a new
155 `Circle` to any arbitrary size.
156
157 # Associated functions
158
159 You can also define associated functions that do not take a `self` parameter.
160 Here’s a pattern that’s very common in Rust code:
161
162 ```rust
163 struct Circle {
164 x: f64,
165 y: f64,
166 radius: f64,
167 }
168
169 impl Circle {
170 fn new(x: f64, y: f64, radius: f64) -> Circle {
171 Circle {
172 x: x,
173 y: y,
174 radius: radius,
175 }
176 }
177 }
178
179 fn main() {
180 let c = Circle::new(0.0, 0.0, 2.0);
181 }
182 ```
183
184 This ‘associated function’ builds a new `Circle` for us. Note that associated
185 functions are called with the `Struct::function()` syntax, rather than the
186 `ref.method()` syntax. Some other languages call associated functions ‘static
187 methods’.
188
189 # Builder Pattern
190
191 Let’s say that we want our users to be able to create `Circle`s, but we will
192 allow them to only set the properties they care about. Otherwise, the `x`
193 and `y` attributes will be `0.0`, and the `radius` will be `1.0`. Rust doesn’t
194 have method overloading, named arguments, or variable arguments. We employ
195 the builder pattern instead. It looks like this:
196
197 ```rust
198 struct Circle {
199 x: f64,
200 y: f64,
201 radius: f64,
202 }
203
204 impl Circle {
205 fn area(&self) -> f64 {
206 std::f64::consts::PI * (self.radius * self.radius)
207 }
208 }
209
210 struct CircleBuilder {
211 x: f64,
212 y: f64,
213 radius: f64,
214 }
215
216 impl CircleBuilder {
217 fn new() -> CircleBuilder {
218 CircleBuilder { x: 0.0, y: 0.0, radius: 1.0, }
219 }
220
221 fn x(&mut self, coordinate: f64) -> &mut CircleBuilder {
222 self.x = coordinate;
223 self
224 }
225
226 fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
227 self.y = coordinate;
228 self
229 }
230
231 fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
232 self.radius = radius;
233 self
234 }
235
236 fn finalize(&self) -> Circle {
237 Circle { x: self.x, y: self.y, radius: self.radius }
238 }
239 }
240
241 fn main() {
242 let c = CircleBuilder::new()
243 .x(1.0)
244 .y(2.0)
245 .radius(2.0)
246 .finalize();
247
248 println!("area: {}", c.area());
249 println!("x: {}", c.x);
250 println!("y: {}", c.y);
251 }
252 ```
253
254 What we’ve done here is make another `struct`, `CircleBuilder`. We’ve defined our
255 builder methods on it. We’ve also defined our `area()` method on `Circle`. We
256 also made one more method on `CircleBuilder`: `finalize()`. This method creates
257 our final `Circle` from the builder. Now, we’ve used the type system to enforce
258 our concerns: we can use the methods on `CircleBuilder` to constrain making
259 `Circle`s in any way we choose.