Trait bounds with impl trait syntax

The other syntax for declaring trait bounds is the impl trait syntax, which is a recent addition to the compiler. Using this syntax, you can also write a generic function with trait bounds like this:

// impl_trait_syntax.rs

use std::fmt::Display;

fn show_me(val: impl Display) {
println!("{}", val);
}

fn main() {
show_me("Trait bounds are awesome");
}

Instead of specifying T: Display, we directly use impl Display. This is the impl trait syntax. This provides advantages in cases where we want to return a complex or unrepresentable type, such as a closure from a function. Without this syntax, you had to return it by putting it behind a pointer using the Box smart pointer type, which involves heap allocation. Closures under the hood are implemented as structs that implement a family of traits. One of these traits is the Fn(T) -> U trait. So, using the impl trait syntax, it's now possible to write functions where we can write something like this: 

// impl_trait_closure.rs

fn lazy_adder(a:u32, b: u32) -> impl Fn() -> u32 {
move || a + b
}

fn main() {
let add_later = lazy_adder(1024, 2048);
println!("{:?}", add_later());
}

In the preceding code, we created a function, lazy_adder, that takes in two numbers and returns a closure that adds two numbers. We then call lazy_adder, passing in two numbers. This creates a closure in add_later but does not evaluate it. In main, we called add_later in the println! macro. We can even have this syntax in both places, like so:

// impl_trait_both.rs

use std::fmt::Display;

fn surround_with_braces(val: impl Display) -> impl Display {
format!("{{{}}}", val)
}

fn main() {
println!("{}", surround_with_braces("Hello"));
}

surround_with_braces takes in anything that is Display and returns a string surrounded with {}. Here, both our return types are impl Display.

The extra braces are there to escape the brace itself, as {} has a special meaning in string formatting for string interpolation.

The impl trait syntax for trait bounds is mostly recommended to be used as return types from functions. Using it in parameter position means that we can't use the turbofish operator. This can cause API incompatibility if some dependent code uses the turbofish operator to invoke one of your crate's methods. It should only be used when we don't have a concrete type available to us, as is the case with closures.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset