Vectors, Strings and HashMaps
## Learning Objectives
- Work with Vec (dynamic arrays)
- Master String manipulation
- Use HashMap for key-value storage
- Choose appropriate collection types
## Vectors
### Creating Vectors
```rust
fn main() {
let v: Vec = Vec::new();
let v = vec![1, 2, 3]; // Using macro
let v = vec![0; 5]; // Five zeros
}
```
### Vector Adding Elements
```rust
fn main() {
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);
v.extend([4, 5, 6]); // Add multiple
v.push_str("hello"); // Error: different type
}
```
### Reading Elements
```rust
fn main() {
let v = vec![1, 2, 3, 4, 5];
let third = v[2]; // Panics if out of bounds
let third = v.get(2); // Returns Option<&T>
let third = v.get(2).unwrap(); // Returns 3
match v.get(10) {
Some(n) => println!("{}", n),
None => println!("Not found"),
}
}
```
### Vector Iterating
```rust
fn main() {
let v = vec![1, 2, 3];
// Immutable borrow
for i in &v {
println!("{}", i);
}
// Mutable borrow
let mut v = vec![1, 2, 3];
for i in &mut v {
*i *= 2; // Double each element
}
}
```
### Useful Methods
```rust
fn main() {
let mut v = vec![1, 2, 3, 4, 5];
v.pop(); // Remove and return last
v.remove(1); // Remove at index
v.insert(0, 10); // Insert at index
v.clear(); // Remove all
v.len(); // Length
v.is_empty(); // Check if empty
v.contains(&3); // Check for value
v.iter().position(|&x| x == 3); // Find index
v.sort(); // Sort (requires PartialOrd)
v.reverse();
}
```
### Using Enum in Vector
```rust
fn main() {
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12)),
];
}
```
## Strings
### Creating Strings
```rust
fn main() {
let s = String::new(); // Empty string
let s = "initial".to_string(); // From literal
let s = String::from("initial"); // From literal
let s = String::with_capacity(10); // Pre-allocated
}
```
### Updating Strings
```rust
fn main() {
let mut s = String::from("hello");
s.push(' '); // Add char
s.push_str("world"); // Add string slice
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1 is moved, s2 borrowed
// println!("{}", s1); // Error: s1 moved
let s1 = String::from("Hello");
let s2 = String::from("world");
let s3 = format!("{} {}", s1, s2); // format! macro
}
```
### String Slices
```rust
fn main() {
let s = String::from("hello world");
let hello = &s[0..5]; // hello
let world = &s[6..11]; // world
let hello = &s[..5]; // hello
let world = &s[6..]; // world
}
```
### Iterating Over Strings
```rust
fn main() {
let s = "hello";
for c in s.chars() {
println!("{}", c);
}
for b in s.bytes() {
println!("{}", b);
}
}
```
### Useful String Methods
```rust
fn main() {
let s = " hello world ";
s.trim(); // Trim whitespace
s.to_uppercase(); // UPPERCASE
s.to_lowercase(); // lowercase
s.len(); // Byte length
s.is_empty(); // Check if empty
"hello".contains("ell"); // true
"hello".starts_with("he"); // true
"hello".ends_with("lo"); // true
"hello".replace("l", "r"); // herro
let parts: Vec<&str> = "a,b,c".split(',').collect();
}
```
### String from User Input
```rust
use std::io;
fn main() {
let mut input = String::new();
io::stdin().read_line(&mut input)
.expect("Failed to read line");
let input = input.trim(); // Remove newline
println!("You entered: {}", input);
}
```
## HashMaps
### Creating HashMaps
```rust
use std::collections::HashMap;
fn main() {
let mut map: HashMap = HashMap::new();
let map = HashMap::from([
("a".to_string(), 1),
("b".to_string(), 2),
]);
}
```
### HashMap Adding Elements
```rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
// Only insert if key doesn't exist
scores.entry(String::from("Blue")).or_insert(20);
scores.entry(String::from("Red")).or_insert(30);
}
```
### Accessing Values
```rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
let team = String::from("Blue");
let score = scores.get(&team); // Option<&i32>
match scores.get(&team) {
Some(s) => println!("Score: {}", s),
None => println!("Team not found"),
}
}
```
### HashMap Iterating
```rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("Blue", 10);
scores.insert("Yellow", 50);
// Iterate over key-value pairs
for (key, value) in &scores {
println!("{}: {}", key, value);
}
// Iterate over keys
for key in scores.keys() {
println!("{}", key);
}
// Iterate over values
for value in scores.values() {
println!("{}", value);
}
}
```
### Updating Values
```rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("Blue", 10);
// Overwrite
scores.insert("Blue", 25); // Blue: 25
// Only insert if key doesn't exist
scores.entry("Yellow").or_insert(50); // Yellow: 50
scores.entry("Yellow").or_insert(100); // Yellow: 50 (unchanged)
// Update based on old value
let text = "hello world wonderful world";
let mut word_count = HashMap::new();
for word in text.split_whitespace() {
let count = word_count.entry(word).or_insert(0);
*count += 1;
}
}
```
### Removing Entries
```rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("Blue", 10);
scores.remove("Blue"); // Remove entry
scores.clear(); // Remove all
}
```
## Choosing Collection Types
### Vec vs Array
- Use **array** when size is fixed at compile time
- Use **Vec** when size may grow or shrink
### String vs &str
- Use **&str** (string slice) when you don't need ownership
- Use **String** when you need ownership or to build strings
### HashMap vs Vec
- Use **HashMap** when you need key-value lookups
- Use **Vec** when you need ordered data or indices
### HashSet
```rust
use std::collections::HashSet;
fn main() {
let mut set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(3);
set.contains(&2); // true
set.remove(&1);
let a = vec![1, 2, 3];
let b = vec![2, 3, 4];
let intersection: Vec<_> = a.iter().filter(|x| b.contains(x)).collect();
let union: Vec<_> = a.iter().chain(b.iter()).collect();
}
```
## Summary
- Vectors (`Vec`) are dynamic arrays
- Use `push` to add, `pop` to remove from end
- Use `get` for safe access, `[]` for panicking access
- Strings (`String`) are growable, `&str` is a view
- Use `format!` to concatenate strings
- `HashMap` stores key-value pairs
- Use `entry().or_insert()` for insert-if-missing
- `HashSet` stores unique values
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →