about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-02-17 15:13:42 -0800
committerAlex Crichton <alex@alexcrichton.com>2015-02-17 15:13:42 -0800
commit311fc36a57575ce42cae77a8aed12e43459a0b92 (patch)
treea189ab54b679e4031401ec0742f992ad9dc17ee9
parentf492095eb4ac061f1b4898b92880095d23dc9c86 (diff)
parentfaf0f5b196ead1b2f3083c14ed4ddeab3bd85063 (diff)
downloadrust-311fc36a57575ce42cae77a8aed12e43459a0b92.tar.gz
rust-311fc36a57575ce42cae77a8aed12e43459a0b92.zip
rollup merge of #22123: steveklabnik/doc_where_clauses
Closes #21859.
-rw-r--r--src/doc/trpl/traits.md90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md
index e091878cf86..52ec012320a 100644
--- a/src/doc/trpl/traits.md
+++ b/src/doc/trpl/traits.md
@@ -273,6 +273,96 @@ One last thing about traits: generic functions with a trait bound use
 dispatched. What's that mean? Check out the chapter on [static and dynamic
 dispatch](static-and-dynamic-dispatch.html) for more.
 
+## Where clause
+
+Writing functions with only a few generic types and a small number of trait
+bounds isn't too bad, but as the number increases, the syntax gets increasingly
+awkward:
+
+```
+use std::fmt::Debug;
+
+fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
+    x.clone();
+    y.clone();
+    println!("{:?}", y);
+}
+```
+
+The name of the function is on the far left, and the parameter list is on the
+far right. The bounds are getting in the way.
+
+Rust has a solution, and it's called a '`where` clause':
+
+```
+use std::fmt::Debug;
+
+fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
+    x.clone();
+    y.clone();
+    println!("{:?}", y);
+}
+
+fn bar<T, K>(x: T, y: K) where T: Clone, K: Clone + Debug {
+    x.clone();
+    y.clone();
+    println!("{:?}", y);
+}
+
+fn main() {
+    foo("Hello", "world");
+    bar("Hello", "workd");
+}
+```
+
+`foo()` uses the syntax we showed earlier, and `bar()` uses a `where` clause.
+All you need to do is leave off the bounds when defining your type parameters,
+and then add `where` after the parameter list. For longer lists, whitespace can
+be added:
+
+```
+use std::fmt::Debug;
+
+fn bar<T, K>(x: T, y: K)
+    where T: Clone,
+          K: Clone + Debug {
+
+    x.clone();
+    y.clone();
+    println!("{:?}", y);
+}
+```
+
+This flexibility can add clarity in complex situations.
+
+`where` is also more powerful than the simpler syntax. For example:
+
+```
+trait ConvertTo<Output> {
+    fn convert(&self) -> Output;
+}
+
+impl ConvertTo<i64> for i32 {
+    fn convert(&self) -> i64 { *self as i32 }
+}
+
+// can be called with T == i32
+fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
+    x.convert()
+}
+
+// can be called with T == i64
+fn inverse<T>() -> T
+        // this is using ConvertTo as if it were "ConvertFrom<i32>"
+        where i32: ConvertTo<T> {
+    1i32.convert()
+}
+```
+
+This shows off the additional feature of `where` clauses: they allow bounds
+where the left-hand side is an arbitrary type (`i32` in this case), not just a
+plain type parameter (like `T`).
+
 ## Our `inverse` Example
 
 Back in [Generics](generics.html), we were trying to write code like this: