Skip to content

Commit 311fc36

Browse files
committed
rollup merge of rust-lang#22123: steveklabnik/doc_where_clauses
Closes rust-lang#21859.
2 parents f492095 + faf0f5b commit 311fc36

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

src/doc/trpl/traits.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,96 @@ One last thing about traits: generic functions with a trait bound use
273273
dispatched. What's that mean? Check out the chapter on [static and dynamic
274274
dispatch](static-and-dynamic-dispatch.html) for more.
275275

276+
## Where clause
277+
278+
Writing functions with only a few generic types and a small number of trait
279+
bounds isn't too bad, but as the number increases, the syntax gets increasingly
280+
awkward:
281+
282+
```
283+
use std::fmt::Debug;
284+
285+
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
286+
x.clone();
287+
y.clone();
288+
println!("{:?}", y);
289+
}
290+
```
291+
292+
The name of the function is on the far left, and the parameter list is on the
293+
far right. The bounds are getting in the way.
294+
295+
Rust has a solution, and it's called a '`where` clause':
296+
297+
```
298+
use std::fmt::Debug;
299+
300+
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
301+
x.clone();
302+
y.clone();
303+
println!("{:?}", y);
304+
}
305+
306+
fn bar<T, K>(x: T, y: K) where T: Clone, K: Clone + Debug {
307+
x.clone();
308+
y.clone();
309+
println!("{:?}", y);
310+
}
311+
312+
fn main() {
313+
foo("Hello", "world");
314+
bar("Hello", "workd");
315+
}
316+
```
317+
318+
`foo()` uses the syntax we showed earlier, and `bar()` uses a `where` clause.
319+
All you need to do is leave off the bounds when defining your type parameters,
320+
and then add `where` after the parameter list. For longer lists, whitespace can
321+
be added:
322+
323+
```
324+
use std::fmt::Debug;
325+
326+
fn bar<T, K>(x: T, y: K)
327+
where T: Clone,
328+
K: Clone + Debug {
329+
330+
x.clone();
331+
y.clone();
332+
println!("{:?}", y);
333+
}
334+
```
335+
336+
This flexibility can add clarity in complex situations.
337+
338+
`where` is also more powerful than the simpler syntax. For example:
339+
340+
```
341+
trait ConvertTo<Output> {
342+
fn convert(&self) -> Output;
343+
}
344+
345+
impl ConvertTo<i64> for i32 {
346+
fn convert(&self) -> i64 { *self as i32 }
347+
}
348+
349+
// can be called with T == i32
350+
fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
351+
x.convert()
352+
}
353+
354+
// can be called with T == i64
355+
fn inverse<T>() -> T
356+
// this is using ConvertTo as if it were "ConvertFrom<i32>"
357+
where i32: ConvertTo<T> {
358+
1i32.convert()
359+
}
360+
```
361+
362+
This shows off the additional feature of `where` clauses: they allow bounds
363+
where the left-hand side is an arbitrary type (`i32` in this case), not just a
364+
plain type parameter (like `T`).
365+
276366
## Our `inverse` Example
277367

278368
Back in [Generics](generics.html), we were trying to write code like this:

0 commit comments

Comments
 (0)