What's the difference between `<T: Trait>` and `where T: Trait`?

余生长醉 提交于 2019-11-27 02:55:46

问题


In the docs for the Send trait, I see both

impl<T> Send for LinkedList<T> 
where
    T: Send, 

and

impl<T: Send> Send for LinkedList<T>

What is the difference between these two syntaxes, and how would it impact my code if I was writing impl declarations for my own trait?


回答1:


Trait bounds defined inside a where clause are a superset of the trait bounds declared inline. The inline style existed before the where clause; the where clause was introduced in RFC 135:

Add where clauses, which provide a more expressive means of specifying trait parameter bounds. [...] The existing bounds notation would remain as syntactic sugar for where clauses.

Here is a list of limitations with the current bounds syntax that are overcome with the where syntax:

  • It cannot express bounds on anything other than type parameters. Therefore, if you have a function generic in T, you can write T:MyTrait to declare that T must implement MyTrait, but you can't write Option<T> : MyTrait or (int, T) : MyTrait. These forms are less commonly required but still important.

  • It does not work well with associated types. This is because there is no space to specify the value of an associated type. Other languages use where clauses (or something analogous) for this purpose.

  • It's just plain hard to read. Experience has shown that as the number of bounds grows, the current syntax becomes hard to read and format.

Since then you can also use higher-ranked trait bounds (for <'a> ...) in a where clause:

fn foo<T, U>()
where
    // higher-ranked trait bounds
    for<'a> T: SomethingElse<'a>,
    // Bound not directly on the generic type
    i32: From<U>,
    T: Iterator,
    // Bound on an associated type
    T::Item: Clone,
    // Just really long
    U: ReallyLong + AnotherReallyLong + WowReallyLong,
{}

If your needs can be met by the inline trait bounds, then there is no impact on your code. If you need the extra powers that only where enables, then you need to use where.


My personal style is to always use the where form. Having a single shape that is also easier to git diff when adding new bounds is worth the extra line of code for me.




回答2:


The where clause documentation now includes the example:

When specifying generic types and bounds separately is clearer:

impl <A: TraitB + TraitC, D: TraitE + TraitF> MyTrait<A, D> for YourType {}

// Expressing bounds with a `where` clause
impl <A, D> MyTrait<A, D> for YourType where
    A: TraitB + TraitC,
    D: TraitE + TraitF {}

shepmaster mentions:

My personal style is to always use the where form.
Having a single shape that is also easier to git diff when adding new bounds is worth the extra line of code for me.

I agree, considering Git 2.23 (Q3 2019) will add rust to its funcname and words boundaries.

See commit 33be7b3 (30 May 2019) by Johannes Sixt (j6t).
See commit d74e786 (16 May 2019) by Marc-André Lureau (``).
(Merged by Junio C Hamano -- gitster -- in commit a41dad4, 21 Jun 2019)

userdiff: add built-in pattern for rust

This adds xfuncname and word_regex patterns for Rust, a quite popular programming language.
It also includes test cases for the xfuncname regex (t4018) and updated documentation.



来源:https://stackoverflow.com/questions/46793494/whats-the-difference-between-t-trait-and-where-t-trait

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!