Though it is possible to write simple Rust programs without impl
-blocks, most Rust developers use impl
-blocks extensively. They allow us to use member methods on structs.
Standing for "implementation," impl
can be used without complex features like dyn or traits. We can use impl
to specify "instance methods" on a struct
.
Here is an example of an impl
-block that is used with an Example struct
. It is common to need to use the self
-keyword as well in an impl
-block.
impl
-block can make code more readable and modular. Fewer types may need to be imported into new Rust files.struct Example { colors: usize, } impl Example { fn test(&self) { // Print colors from self. println!("Colors = {}", self.colors); } } fn main() { let ex = Example { colors: 15 }; // Call test function. ex.test(); }Colors = 15
In some programming languages, calling a function on a type instance may be slower than a top-level function. We test this issue in Rust with impl
.
test_value()
function that is not part of an impl
block (a top-level function).impl
version of the test_value()
function that does the same thing.impl
blocks.use std::time::*; fn test_value(value: &str) { if value != "bird" { panic!("ERROR"); } } struct Example { value: String, } impl Example { fn test_value(&self) { if self.value != "bird" { panic!("ERROR"); } } } fn main() { if let Ok(max) = "100000000".parse::<usize>() { let value = "bird".to_owned(); let ex = Example { value: "bird".to_owned(), }; // Version 1: test with top-level function. let t0 = Instant::now(); for _ in 0..max { test_value(&value); } println!("{} ms", t0.elapsed().as_millis()); // Version 2: test with function in impl block. let t1 = Instant::now(); for _ in 0..max { ex.test_value(); } println!("{} ms", t1.elapsed().as_millis()); } }34 ms test_value() 33 ms ex.text_value()
Impl blocks and instance functions on structs are an abstraction with zero overhead in Rust. They help organize programs, make them more modular, and are a basis for creating a crate.