Vec
Equals
A common requirement in Rust involves testing whether 2 Vectors or slices have the same element contents and lengths. This can be done with a for
-loop.
But slices have the Eq trait, which means they can be compared with equals expressions. This compares the actual elements, and it is optimized for faster testing than a loop.
We create 2 vectors, each with 3 elements. These vectors have the same exact data, but they are not the same vector—they are separate in memory.
fn main() { let buffer = vec![10, 20, 30]; let mut buffer2 = vec![]; buffer2.push(10); buffer2.push(20); buffer2.push(30); // See if contents of 2 vectors are the same. if buffer == buffer2 { println!("SLICES ARE EQUAL"); } let buffer3 = vec![1000, 2000, 3000]; if buffer != buffer3 { println!("NOT EQUAL"); } }SLICES ARE EQUAL NOT EQUAL
Capacity
exampleCan 2 vectors with different capacities be equal? In this program we find that the capacity is ignored—just the element data and count is compared.
Vec
equality operation is robust and works as expected. It tests element count, and element values.fn main() { // See if capacity affects equality of 2 vectors. let mut vector1 = Vec::with_capacity(6000000); vector1.push(9); let mut vector2 = Vec::with_capacity(10); vector2.push(9); if vector1 == vector2 { println!("VECTORS ARE EQUAL, CAPACITY IGNORED"); } }VECTORS ARE EQUAL, CAPACITY IGNORED
vec
Suppose we want to compare 2 vectors (or slices) in the fastest way possible. Is the equality operator the best choice here?
use std::time::*; fn main() { let max = 1000000; let mut count = 0; let mut count2 = 0; // Create 2 Vectors to compare. let mut buffer = vec![]; for _ in 0..max { buffer.push(5); } let mut buffer2 = vec![]; for _ in 0..max { buffer2.push(5); } // Version 1: test with equals. let now = Instant::now(); if buffer == buffer2 { count += 1; } println!("{} ns", now.elapsed().as_nanos()); // Version 2: test with for-loop. let now = Instant::now(); let mut equal = false; if buffer.len() == buffer2.len() { equal = true; for index in 0..buffer.len() { if buffer[index] != buffer2[index] { equal = false; break; } } } if equal { count2 += 1; } println!("{} ns", now.elapsed().as_nanos()); println!("Counts: {}, {}", count, count2); }274916 ns 797250 ns Counts: 1, 1
Suppose we want to loop over a slice of u8
bytes, and find a specific pattern of bytes in the slice. We could use chained if
-checks on individual bytes.
use std::time::*; fn main() { // The data to test. let mut data = vec![]; for _ in 0..1000000 { data.push(0); data.push(10); data.push(20); data.push(30); } let mut count1 = 0; let mut count2 = 0; // Version 1: use slice-based test. let t0 = Instant::now(); for _ in 0..1000 { for i in 3..data.len() { let slice_here = &data[i - 3..=i]; if slice_here == [0, 10, 20, 30] { count1 += 1; } } } println!("{}", t0.elapsed().as_millis()); // Version 2: Use individual index tests. let t1 = Instant::now(); for _ in 0..1000 { for i in 3..data.len() { if data[i - 3] == 0 && data[i - 2] == 10 && data[i - 1] == 20 && data[i] == 30 { count2 += 1; } } } println!("{}", t1.elapsed().as_millis()); println!("{} {}", count1, count2); }2550 ms (slice equals) 2834 ms 1000000000 1000000000
In Rust we can use Vecs as slices by using a reference. It is usually best to act upon slices as they are more versatile (other things can be slices, not just vectors).
Comparing 2 slices for equality in Rust compares the individual elements and the lengths. It does not consider capacity, and it is much faster than a for
-loop.