Keyword where

source ·
Expand description

Add constraints that must be upheld to use an item.

where allows specifying constraints on lifetime and generic parameters. The RFC introducing where contains detailed information about the keyword.

§Examples

where can be used for constraints with traits:

fn new<T: Default>() -> T {
    T::default()
}

fn new_where<T>() -> T
where
    T: Default,
{
    T::default()
}

assert_eq!(0.0, new());
assert_eq!(0.0, new_where());

assert_eq!(0, new());
assert_eq!(0, new_where());
Run

where can also be used for lifetimes.

This compiles because longer outlives shorter, thus the constraint is respected:

fn select<'short, 'long>(s1: &'short str, s2: &'long str, second: bool) -> &'short str
where
    'long: 'short,
{
    if second { s2 } else { s1 }
}

let outer = String::from("Long living ref");
let longer = &outer;
{
    let inner = String::from("Short living ref");
    let shorter = &inner;

    assert_eq!(select(shorter, longer, false), shorter);
    assert_eq!(select(shorter, longer, true), longer);
}
Run

On the other hand, this will not compile because the where 'b: 'a clause is missing: the 'b lifetime is not known to live at least as long as 'a which means this function cannot ensure it always returns a valid reference:

fn select<'a, 'b>(s1: &'a str, s2: &'b str, second: bool) -> &'a str
{
    if second { s2 } else { s1 }
}
Run

where can also be used to express more complicated constraints that cannot be written with the <T: Trait> syntax:

fn first_or_default<I>(mut i: I) -> I::Item
where
    I: Iterator,
    I::Item: Default,
{
    i.next().unwrap_or_else(I::Item::default)
}

assert_eq!(first_or_default([1, 2, 3].into_iter()), 1);
assert_eq!(first_or_default(Vec::<i32>::new().into_iter()), 0);
Run

where is available anywhere generic and lifetime parameters are available, as can be seen with the Cow type from the standard library:

pub enum Cow<'a, B>
where
    B: ToOwned + ?Sized,
{
    Borrowed(&'a B),
    Owned(<B as ToOwned>::Owned),
}
Run