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