about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/doc/trpl/method-syntax.md114
1 files changed, 112 insertions, 2 deletions
diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md
index 3d8de00991c..e6570c2ee74 100644
--- a/src/doc/trpl/method-syntax.md
+++ b/src/doc/trpl/method-syntax.md
@@ -18,6 +18,8 @@ x.foo().bar().baz();
 Luckily, as you may have guessed with the leading question, you can! Rust provides
 the ability to use this *method call syntax* via the `impl` keyword.
 
+## Method calls
+
 Here's how it works:
 
 ```{rust}
@@ -56,11 +58,56 @@ other parameter. Because we know it's a `Circle`, we can access the `radius`
 just like we would with any other struct. An import of π and some
 multiplications later, and we have our area.
 
+## Chaining method calls
+
+So, now we know how to call a method, such as `foo.bar()`. But what about our
+original example, `foo.bar().baz()`? This is called 'method chaining', and we
+can do it by returning `self`.
+
+```
+struct Circle {
+    x: f64,
+    y: f64,
+    radius: f64,
+}
+
+impl Circle {
+    fn area(&self) -> f64 {
+        std::f64::consts::PI * (self.radius * self.radius)
+    }
+
+    fn grow(&self) -> Circle {
+        Circle { x: self.x, y: self.y, radius: (self.radius * 10.0) }
+    }
+}
+
+fn main() {
+    let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
+    println!("{}", c.area());
+
+    let d = c.grow().area();
+    println!("{}", d);
+}
+```
+
+Check the return type:
+
+```
+# struct Circle;
+# impl Circle {
+fn grow(&self) -> Circle {
+# Circle } }
+```
+
+We just say we're returning a `Circle`. With this, we can grow a new circle
+that's twice as big as the old one.
+
+## Static methods
+
 You can also define methods that do not take a `self` parameter. Here's a
 pattern that's very common in Rust code:
 
-```{rust}
-# #![allow(non_shorthand_field_patterns)]
+```
 struct Circle {
     x: f64,
     y: f64,
@@ -86,3 +133,66 @@ This *static method* builds a new `Circle` for us. Note that static methods
 are called with the `Struct::method()` syntax, rather than the `ref.method()`
 syntax.
 
+## Builder Pattern
+
+Let's say that we want our users to be able to create Circles, but we will
+allow them to only set the properties they care about. Otherwise, the `x`
+and `y` attributes will be `0.0`, and the `radius` will be `1.0`. Rust doesn't
+have method overloading, named arguments, or variable arguments. We employ
+the builder pattern instead. It looks like this:
+
+```
+struct Circle {
+    x: f64,
+    y: f64,
+    radius: f64,
+}
+
+impl Circle {
+    fn area(&self) -> f64 {
+        std::f64::consts::PI * (self.radius * self.radius)
+    }
+}
+
+struct CircleBuilder {
+    coordinate: f64,
+    radius: f64,
+}
+
+impl CircleBuilder {
+    fn new() -> CircleBuilder {
+        CircleBuilder { coordinate: 0.0, radius: 0.0, }
+    }
+
+    fn coordinate(&mut self, coordinate: f64) -> &mut CircleBuilder {
+	self.coordinate = coordinate;
+	self
+    }
+
+    fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
+	self.radius = radius;
+	self
+    }
+
+    fn finalize(&self) -> Circle {
+        Circle { x: self.coordinate, y: self.coordinate, radius: self.radius }
+    }
+}
+
+fn main() {
+    let c = CircleBuilder::new()
+                .coordinate(10.0)
+                .radius(5.0)
+                .finalize();
+
+
+    println!("area: {}", c.area());
+}
+```
+
+What we've done here is make another struct, `CircleBuilder`. We've defined our
+builder methods on it. We've also defined our `area()` method on `Circle`. We
+also made one more method on `CircleBuilder`: `finalize()`. This method creates
+our final `Circle` from the builder. Now, we've used the type system to enforce
+our concerns: we can use the methods on `CircleBuilder` to constrain making
+`Circle`s in any way we choose.