Loop over chars. Whenever we need to use strings in Rust, we usually will need to loop over their chars and modify them in some way. Rust provides iterators over strings.
For-in loop. With a for-in loop, we can use an iterator with minimal syntax to loop over a string. We can use the loop to create a new string, or perform other logic.
First example. To begin, we have a simple string that contains the word "abc." We call chars() to get an iterator of all the characters in this string.
Detail We use a for-in loop directly on the iterator returned by chars. Each time the loop executes, the variable is set to a character.
fn main() {
let test = "abc";
// Get chars.
let values = test.chars();
// Use for-in loop to print all chars.
for c in values {
println!("CHARACTER: {}", c)
}
}CHARACTER: a
CHARACTER: b
CHARACTER: c
Reverse loop. We can change how the iterator returned by chars() loops over characters. With rev(), for example, we can loop over the chars in reverse order.
fn main() {
let test = "cat";
// Loop over chars backwards.
for c in test.chars().rev() {
println!("REV: {}", c)
}
}REV: t
REV: a
REV: c
Bytes. Suppose we have an ASCII-only string, and want to get each byte in a loop. The bytes() function is ideal here. It returns a u8 on each iteration.
fn print_bytes(value: &str) {
// Loop over bytes.
for b in value.bytes() {
println!("BYTE: {b}");
}
}
fn main() {
print_bytes("rust");
}BYTE: 114
BYTE: 117
BYTE: 115
BYTE: 116
Char vec. Suppose we want to access each character in a string by its index. We may want to access other indexes at the same time. We can convert a string to a Vector.
And We can then loop over the indexes of the vector, accessing each char. We can access adjacent chars at different indexes in the same loop.
fn main() {
let name = "cat";
let letters = name.chars().collect::<Vec<char>>();
// Loop over characters by index.// We can access other indexes more easily this way.
for i in 0..letters.len() {
println!("{}", letters[i]);
}
}c
a
t
Chars, bytes benchmark. Suppose we have a string we know is only ASCII. Should we use chars() or bytes() to iterate over the string?
Version 1 This version of the code uses the chars() function to access each char in the string. It tests for the letter "e".
Version 2 This code does the same thing as version 1, but uses the bytes() function to handle bytes.
Result Using bytes() is almost twice as fast as using chars. If a string is only ASCII, bytes() should be considered.
use std::time::*;
fn main() {
let mut example = String::new();
example.push_str("yellow bird ");
example.push_str("and green frog");
// Version 1: use chars.
let t0 = Instant::now();
let mut count = 0;
for _ in 0..1000000 {
for c in example.chars() {
if c == 'e' {
count += 1;
}
}
}
println!("{}", t0.elapsed().as_millis());
// Version 2: use bytes.
let t1 = Instant::now();
let mut count2 = 0;
for _ in 0..1000000 {
for b in example.bytes() {
if b == b'e' {
count2 += 1;
}
}
}
println!("{}", t1.elapsed().as_millis());
println!("{count} {count2}");
}20 ms (chars)
11 ms (bytes)
3000000 3000000
A review. We cannot directly access the chars in a string, as each char may be a different size. But with iterators, we can loop over and test each char in order.
Dot Net Perls is a collection of pages with code examples, which are updated to stay current. Programming is an art, and it can be learned from examples.
Donate to this site to help offset the costs of running the server. Sites like this will cease to exist if there is no financial support for them.
Sam Allen is passionate about computer languages, and he maintains 100% of the material available on this website. He hopes it makes the world a nicer place.
This page was last updated on Feb 12, 2023 (new example).