Rust Strings, Vectors and HashMaps
Rust's standard library gives you growable collections: String for text, Vec for lists and HashMap for key and value pairs.
String and &str
Rust has two main text types:
| Type | What it is | Example |
|---|---|---|
&str | A borrowed piece of text, often fixed | "Lahore" |
String | An owned text that can grow | String::from("Lahore") |
Text in double quotes is a &str. Turn it into a String with String::from() or .to_string().
Example
fn main() {
let mut msg = String::from("Hello");
msg.push_str(", Karachi");
msg.push('!');
println!("{}", msg);
println!("{}", msg.len());
println!("{}", msg.to_uppercase());
println!("{}", msg.contains("Kar"));
println!("{}", msg.replace("Hello", "Salam"));
let first = String::from("Ali");
let last = "Khan";
let full = format!("{} {}", first, last);
println!("{}", full);
}Hello, Karachi! 15 HELLO, KARACHI! true Salam, Karachi! Ali Khan
format! works like println! but returns a String instead of printing it.
Write function parameters as &str instead of &String. A &str parameter accepts both text literals and borrowed String values.
Splitting and Characters
Example
fn main() {
let line = "rice,daal,tea";
for item in line.split(',') {
println!("{}", item);
}
let word = "Rust";
for c in word.chars() {
print!("{} ", c);
}
println!();
println!("{}", " trim me ".trim());
}rice daal tea R u s t trim me
Vectors
A Vec<T> is a list that can grow. The vec! macro creates one quickly.
Example
fn main() {
let mut marks = vec![70, 85];
marks.push(92);
marks.push(60);
println!("{:?}", marks);
println!("Count: {}", marks.len());
println!("First: {}", marks[0]);
let last = marks.pop();
println!("{:?}", last);
let total: i32 = marks.iter().sum();
println!("Total: {}", total);
for m in &marks {
println!("Mark: {}", m);
}
match marks.get(10) {
Some(m) => println!("Found {}", m),
None => println!("No mark at index 10"),
}
}[70, 85, 92, 60] Count: 4 First: 70 Some(60) Total: 247 Mark: 70 Mark: 85 Mark: 92 No mark at index 10
marks[10]would crash the program.marks.get(10)returns anOptioninstead, which is safer.for m in &marksborrows the vector, so you can still usemarksafter the loop.
HashMap
A HashMap stores values by key. You need to import it with use.
Example
use std::collections::HashMap;
fn main() {
let mut prices = HashMap::new();
prices.insert("Samosa", 40);
prices.insert("Chai", 60);
prices.insert("Chai", 70);
println!("{}", prices.len());
if let Some(p) = prices.get("Chai") {
println!("Chai costs Rs {}", p);
}
match prices.get("Pizza") {
Some(p) => println!("Pizza costs Rs {}", p),
None => println!("Pizza is not on the menu"),
}
let mut counts = HashMap::new();
for word in "a b a c a".split(' ') {
*counts.entry(word).or_insert(0) += 1;
}
println!("a appears {} times", counts["a"]);
}2 Chai costs Rs 70 Pizza is not on the menu a appears 3 times
Inserting the same key twice replaces the old value. entry().or_insert() adds a key only if it is missing, which is perfect for counting.
A HashMap has no fixed order. Looping over it may give the keys in any order.
Exercise
Exercise
Which call adds the number 5 to the end of let mut v = vec![1, 2];?
