Каков синтаксис и семантика ключевого слова `where`?

К сожалению, документации Rust относительно where очень не хватает. Ключевое слово появляется только в одном или двух несвязанных примерах в ссылке.

  • Какая семантическая разница делает where в следующем коде? Есть ли вообще разница? Какая форма является предпочтительной?

    fn double_a<T>(a:T) -> T where T:std::num::Int {
        a+a
    }
    
    fn double_b<T: std::num::Int>(a:T) -> T {
        a+a
    }
    
  • В реализации черты CharEq кажется, что where используется как своего рода "селектор" для реализации Trait для всего, что соответствует некоторому типу закрытия. Правильно ли я?

Есть ли способ получить лучшую, более полную картину where? (полная спецификация использования и синтаксис)

Ответ 1

В вашем примере эти два кода строго эквивалентны.

Были предложены предложения where, чтобы обеспечить более выразительную проверку границ, например:

fn foo<T>(a: T) where Bar<T>: MyTrait { /* ... */ }

Это невозможно, используя только старый синтаксис.

Использование where вместо исходного синтаксиса обычно предпочтительнее для читаемости, даже если старый синтаксис все еще можно использовать.

Вы можете себе представить, например, такие конструкции, как

fn foo<A, B, C>(a: A, b: B, c: C)
    where A: SomeTrait + OtherTrait,
          B: ThirdTrait<A>+ OtherTrait,
          C: LastTrait<A, B>
{
    /* stuff here */
}

которые гораздо читабельны таким образом, даже если они все еще могут быть выражены с использованием старого синтаксиса.

Для вашего вопроса о признаке CharEq, код:

impl<F> CharEq for F where F: FnMut(char) -> bool {
    #[inline]
    fn matches(&mut self, c: char) -> bool { (*self)(c) }

    #[inline]
    fn only_ascii(&self) -> bool { false }
}

Это буквально означает: реализация признака CharEq для всех типов F, которые уже реализуют признак FnMut(char) -> bool (т.е. замыкание или функцию, принимающую char и возвращающую bool).

Для более подробной информации вы можете посмотреть RFC, в котором представлены предложения where: https://github.com/rust-lang/rfcs/pull/135