diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index e091878cf86ec..52ec012320aa3 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(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(x: T, y: K) { + x.clone(); + y.clone(); + println!("{:?}", y); +} + +fn bar(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(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 { + fn convert(&self) -> Output; +} + +impl ConvertTo for i32 { + fn convert(&self) -> i64 { *self as i32 } +} + +// can be called with T == i32 +fn normal>(x: &T) -> i64 { + x.convert() +} + +// can be called with T == i64 +fn inverse() -> T + // this is using ConvertTo as if it were "ConvertFrom" + where i32: ConvertTo { + 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: