Common Collections
The notes reflect the topics in Chapter 8
Vector
Our old friend std::vector here. Nothing special, just some Rust syntax here.
fn main() {
// Create a vector, just like C++ normal constructor & initilaizer list
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3]; // (1)
// push_back
let mut v = Vec::new();
v.push(5);
v.push(6);
// Read element
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {}", third);
match v.get(2) {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
// Iterate
for i in &v {
println!("{}", i);
}
for i in &mut v {
*i += 50; // Note the * here
}
}- Why does this need to be a macro? That’s because there’s no variadic template in Rust (and I don’t think C++‘s way of recursive template metaprogramming is beautiful). So to make a function take arbitary number of parameters, you need to use macro.
Note we can use enum to put in various types in vector, just like
std::variant. enum is a tagged union though, so its size is slightly bigger
than the largest data it holds (as it need to store which type is being stored).
String
Normal string, but not integer indexable.
fn main() {
// Creating a new string
let mut s = String::new();
let s = "initial contents".to_string();
let s = String::from("initial contents");
// Updating a string
let mut s = String::from("foo");
s.push_str("bar");
s.push('l'); // (1)
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used (2)
let s = format!("{}-{}-{}", s1, s2, s3);
// No integer indexing (3)
// Slicing strings
let hello = "Здравствуйте";
let s = &hello[0..4];
// Iterate over
for c in "नमस्ते".chars() {
println!("{}", c);
}
for c in "नमस्ते".bytes() {
println!("{}", c);
}
}-
Why we have both
push_strandpush? That’s because there’s no overload in Rust. What we have is trait. But trait can’t save us in this case. String and char doesn’t share any common traits. If we useenumhere, there’ll be performance issues. -
The signature is like
fn add(self, s: &str) -> String { -
UTF-8 string is tricky. The UTF-8 characters can have different byte length. And that’s the reason Rust’s string indexing is not a O(n) operation.
- Python: Sacrifice memory, so that all the characters have the same length. It also determine whether to use ASCII or UTF-8 under the hood automatically. See here for more details.
- C++: Has some support, but indexing is on byte level.
- Emacs Lisp, Julia and Go: Either doing “optimization”, or act kinda like C++. See here for more details.
HashMap
fn main() {
use std::collections::HashMap;
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
// Insert
let mut map = HashMap::new();
map.insert(field_name, field_value);
// field_name and field_value are invalid at this point, try using them and
// see what compiler error you get!
// Get
let field_name = "Favorite color".to_string();
let value = scores.get(&field_name);
for (key, value) in &map{
println!("{}: {}", key, value);
}
}