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