Skip to content

← Generics and Traits step 4 of 24

Easy Primitives

where clauses and the bound you cannot write inline

These two signatures mean exactly the same thing:

pub fn summarise<T: Display>(items: Vec<T>) -> String

pub fn summarise<T>(items: Vec<T>) -> String
where
    T: Display,

So where looks like a style preference for people who dislike long angle brackets. It is not. where is strictly more expressive, and the reason matters the first time you get stuck.

Inline bounds can only be attached to a type parameter — a name inside the <...>. A where clause can constrain any type expression at all:

where
    I: IntoIterator,
    I::Item: Display,     // <- no way to say this inline
    Vec<T>: Clone,        // <- nor this

I::Item is an associated type: an output of the IntoIterator impl, not a parameter you declared. There is nowhere in <I> to hang : Display off it. Once you know that, a whole family of “I cannot express this” moments disappears.

Your task

pub fn summarise<T>(items: Vec<T>) -> String
where
    T: Display,

pub fn summarise_any<I>(items: I) -> String
where
    I: IntoIterator,
    I::Item: Display,

pub fn run(nums: Vec<i64>, words: Vec<String>) -> Vec<String>

Both summarisers render the same shape: the count, then the items joined with ", ". For [1, 2, 3] that is "3 items: 1, 2, 3". An empty input gives "0 items: " — note the trailing space; the format string is uniform and nothing special-cases empty.

run returns [summarise(nums), summarise_any(words)].

Two gates you must pass through

1. Clippy will not let you write the bound twice. The starter’s first function has <T: Display> and where T: Display, and the build fails:

error: bound is defined in more than one place
  |
5 | pub fn summarise<T: Display>(items: Vec<T>) -> String
  |                  ^
7 |     T: Display,
  |     ^

That is clippy::multiple_bound_locations, and it is default-on. It bites learners mid-refactor: you add a second bound in a where clause, forget the inline one is still there, and the build stops. Pick one location.

2. The second function does not know what it is iterating. I: IntoIterator says “you can loop over this” and nothing more, so calling .to_string() on an item fails:

error[E0599]: `<I as IntoIterator>::Item` doesn't implement `Display`
   = note: the following trait bounds were not satisfied:
           `<I as IntoIterator>::Item: Display`

The fix is one line — but only in the where clause. Try to put it in the angle brackets and you will not even get a bound error; you will get a parse failure, because that syntax does not exist.

A note on the nursery

You may have read about clippy::type_repetition_in_bounds and clippy::trait_duplication_in_bounds. Both are nursery lints: allow by default, so they will not fire here and you should not count on them. The one that actually gates you is multiple_bound_locations.

Remember the grade is compile + tests + clippy -D warnings.