]> git.lizzy.rs Git - rust.git/blob - src/doc/trpl/method-syntax.md
Rollup merge of #23751 - tshepang:do-not-hardcode-the-growth, r=Manishearth
[rust.git] / src / doc / trpl / 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(x)));
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 x.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 # #![feature(core)]
27 struct Circle {
28     x: f64,
29     y: f64,
30     radius: f64,
31 }
32
33 impl Circle {
34     fn area(&self) -> f64 {
35         std::f64::consts::PI * (self.radius * self.radius)
36     }
37 }
38
39 fn main() {
40     let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
41     println!("{}", c.area());
42 }
43 ```
44
45 This will print `12.566371`.
46
47 We've made a struct that represents a circle. We then write an `impl` block,
48 and inside it, define a method, `area`. Methods take a  special first
49 parameter, of which there are three variants: `self`, `&self`, and `&mut self`.
50 You can think of this first parameter as being the `x` in `x.foo()`. The three
51 variants correspond to the three kinds of thing `x` could be: `self` if it's
52 just a value on the stack, `&self` if it's a reference, and `&mut self` if it's
53 a mutable reference. We should default to using `&self`, as it's the most
54 common. Here's an example of all three variants:
55
56 ```rust
57 struct Circle {
58     x: f64,
59     y: f64,
60     radius: f64,
61 }
62
63 impl Circle {
64     fn reference(&self) {
65        println!("taking self by reference!");
66     }
67
68     fn mutable_reference(&mut self) {
69        println!("taking self by mutable reference!");
70     }
71
72     fn takes_ownership(self) {
73        println!("taking ownership of self!");
74     }
75 }
76 ```
77
78 Finally, as you may remember, the value of the area of a circle is `π*r²`.
79 Because we took the `&self` parameter to `area`, we can use it just like any
80 other parameter. Because we know it's a `Circle`, we can access the `radius`
81 just like we would with any other struct. An import of π and some
82 multiplications later, and we have our area.
83
84 ## Chaining method calls
85
86 So, now we know how to call a method, such as `foo.bar()`. But what about our
87 original example, `foo.bar().baz()`? This is called 'method chaining', and we
88 can do it by returning `self`.
89
90 ```
91 # #![feature(core)]
92 struct Circle {
93     x: f64,
94     y: f64,
95     radius: f64,
96 }
97
98 impl Circle {
99     fn area(&self) -> f64 {
100         std::f64::consts::PI * (self.radius * self.radius)
101     }
102
103     fn grow(&self, increment: f64) -> Circle {
104         Circle { x: self.x, y: self.y, radius: self.radius + increment }
105     }
106 }
107
108 fn main() {
109     let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
110     println!("{}", c.area());
111
112     let d = c.grow(2.0).area();
113     println!("{}", d);
114 }
115 ```
116
117 Check the return type:
118
119 ```
120 # struct Circle;
121 # impl Circle {
122 fn grow(&self) -> Circle {
123 # Circle } }
124 ```
125
126 We just say we're returning a `Circle`. With this method, we can grow a new
127 circle to any arbitrary size.
128
129 ## Static methods
130
131 You can also define methods that do not take a `self` parameter. Here's a
132 pattern that's very common in Rust code:
133
134 ```
135 struct Circle {
136     x: f64,
137     y: f64,
138     radius: f64,
139 }
140
141 impl Circle {
142     fn new(x: f64, y: f64, radius: f64) -> Circle {
143         Circle {
144             x: x,
145             y: y,
146             radius: radius,
147         }
148     }
149 }
150
151 fn main() {
152     let c = Circle::new(0.0, 0.0, 2.0);
153 }
154 ```
155
156 This *static method* builds a new `Circle` for us. Note that static methods
157 are called with the `Struct::method()` syntax, rather than the `ref.method()`
158 syntax.
159
160 ## Builder Pattern
161
162 Let's say that we want our users to be able to create Circles, but we will
163 allow them to only set the properties they care about. Otherwise, the `x`
164 and `y` attributes will be `0.0`, and the `radius` will be `1.0`. Rust doesn't
165 have method overloading, named arguments, or variable arguments. We employ
166 the builder pattern instead. It looks like this:
167
168 ```
169 # #![feature(core)]
170 struct Circle {
171     x: f64,
172     y: f64,
173     radius: f64,
174 }
175
176 impl Circle {
177     fn area(&self) -> f64 {
178         std::f64::consts::PI * (self.radius * self.radius)
179     }
180 }
181
182 struct CircleBuilder {
183     coordinate: f64,
184     radius: f64,
185 }
186
187 impl CircleBuilder {
188     fn new() -> CircleBuilder {
189         CircleBuilder { coordinate: 0.0, radius: 0.0, }
190     }
191
192     fn coordinate(&mut self, coordinate: f64) -> &mut CircleBuilder {
193         self.coordinate = coordinate;
194         self
195     }
196
197     fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
198         self.radius = radius;
199         self
200     }
201
202     fn finalize(&self) -> Circle {
203         Circle { x: self.coordinate, y: self.coordinate, radius: self.radius }
204     }
205 }
206
207 fn main() {
208     let c = CircleBuilder::new()
209                 .coordinate(10.0)
210                 .radius(5.0)
211                 .finalize();
212
213
214     println!("area: {}", c.area());
215 }
216 ```
217
218 What we've done here is make another struct, `CircleBuilder`. We've defined our
219 builder methods on it. We've also defined our `area()` method on `Circle`. We
220 also made one more method on `CircleBuilder`: `finalize()`. This method creates
221 our final `Circle` from the builder. Now, we've used the type system to enforce
222 our concerns: we can use the methods on `CircleBuilder` to constrain making
223 `Circle`s in any way we choose.