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?
A trait tells the Rust compiler about functionality a particular type has and can share with other types. Traits are an abstract definition of shared behavior amongst different types. So, we can say that traits are to Rust what interfaces are to Java or abstract classes are to C++.
Trait and lifetime bounds provide a way for generic items to restrict which types and lifetimes are used as their parameters. Bounds can be provided on any type in a where clause.
Traits can't have fields. If you want to provide access to a field from a trait, you need to define a method in that trait (like, say, get_blah ).
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 forwhere
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 writeT:MyTrait
to declare thatT
must implementMyTrait
, but you can't writeOption<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
.
See also:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With