Contains
The Rust clippy tool advises us to replace if
-statements that test values between two other values. The contains()
function can be used.
But will contains, a function call, perform as well as two if
-checks? We review the syntax of using contains on a range, and benchmark contains.
Contains
exampleTo begin, we have an end-inclusive range in this program. We parse in the number 50. Then we test to see if that number is between 20 and 70 (including 70).
contains()
check succeeded.fn main() { if let Ok(test) = "50".parse() { // See if value is between 20 and 70 (including 70). if (20..=70).contains(&test) { println!("BETWEEN 20 and 70"); } // Not reached. if (0..=5).contains(&test) { println!("?"); } } }BETWEEN 20 and 70
Contains
benchmarkSuppose we have a function that would use the contains()
function many times. Does this cause any performance problem in Rust?
test_contains
which has 2 calls to contains()
in it.if
-statements. Clippy will encourage us to rewrite this version to the other version.contains()
has no performance issue.use std::time::*; fn test_contains(value: i32) -> usize { if (10..=20).contains(&value) { return 1; } if (50..=100).contains(&value) { return 2; } 0 } fn test_if(value: i32) -> usize { if value >= 10 && value <= 20 { return 1; } if value >= 50 && value <= 100 { return 2; } 0 } fn main() { if let Ok(max) = "20000000".parse() { let mut sum1 = 0; let mut sum2 = 0; // Version 1: contains. let t0 = Instant::now(); for i in 0..max { sum1 += test_contains(i as i32); } println!("{}", t0.elapsed().as_millis()); // Version 2: if. let t1 = Instant::now(); for i in 0..max { sum2 += test_if(i as i32); } println!("{}", t1.elapsed().as_millis()); println!("{} = {}", sum1, sum2); } }10 ms (contains) 10 ms 113 = 113
There is a contains function on Strings in Rust. This is similar to calling Find
, but it returns a bool
so it is easier to use in an if
-statement.
fn main() { let source = "linux computer"; // See if this string exists in the source string. if source.contains("computer") { println!("CONTAINS COMPUTER"); } // This string is not found. if source.contains("desk") { println!("Not reached"); } }CONTAINS COMPUTER
A main benefit to Rust is its concept of zero-cost abstractions. When we rewrite if
-statements to include contains()
calls, no performance cost is paid—and our meaning may be clearer.