Trait bounds in Rust are used to constrain generic types by the properties that must be implemented for a specific trait. This allows the use of trait methods and properties within generic functions or types.
The main approaches:
Using the syntax T: SomeTrait in function parameters:
fn print_debug<T: std::fmt::Debug>(item: T) { println!("{:?}", item); }
Using the where keyword to improve readability:
fn print_multiple<T, U>(a: T, b: U) where T: std::fmt::Debug, U: std::fmt::Display, { println!("a = {:?}, b = {}", a, b); }
The where syntax is particularly useful for multiple and lengthy constraints. Trait bounds are needed for the compiler to guarantee that certain methods/properties are definitely available for a particular generic parameter.
Question: What happens if you try to call a trait method on a generic type without a trait bound, even if it is known that this type implements the required trait?
Answer: Rust does not allow using trait methods for generics without an explicit trait bound, even if the type implements it. Example of an error:
fn show(x: T) { println!("{}", x.to_string()); // Error: the compiler does not know that T: ToString }
The compiler will issue an error about the inability to guarantee the existence of the method. The only correct way is to add T: ToString.
Story
In a large JSON serialization library, a developer did not add the required trait bound T: Serialize for the generics serialization function. As a result, the generic function did not allow using serialization methods; clients were misled by an incorrect compiler error.
Story
When migrating code from simple types to generics in a network library, the trait bound on the type parameterizing the structure was missed. This led to the inability to use methods of the structure in generic functions without excessive code duplication.
Story
In an open-source project, they decided to shorten declarations by hiding trait bounds in internal modules. This then led to API users being unable to know which traits were actually required and receiving unclear compiler messages when using the library.