3. Data Structures and Types#
Learn how to organize and structure your data effectively.
3.1. How do I define my own custom data types, like struct in C++ or classes in Python?#
You can group related data fields together into a single type, just like structs in C++ or classes in Python.
Grouping related data:
struct Person {
name: String,
age: u32,
email: String,
}
fn main() {
let person = Person {
name: String::from("Alice"),
age: 30,
email: String::from("alice@example.com"),
};
println!("Name: {}", person.name);
println!("Age: {}", person.age);
println!("Email: {}", person.email);
}
Compare to C++:
struct Person {
std::string name;
unsigned int age;
std::string email;
};
int main() {
Person person = {"Alice", 30, "alice@example.com"};
std::cout << "Name: " << person.name << std::endl;
}
Compare to Python:
class Person:
def __init__(self, name, age, email):
self.name = name
self.age = age
self.email = email
person = Person("Alice", 30, "alice@example.com")
print(f"Name: {person.name}")
Creating different choices for a type:
Sometimes you need a type that can be one of several different things. Like a traffic light that can be red, yellow, or green.
enum Status {
Active,
Inactive,
Pending,
}
enum Message {
Text(String),
Image(String, u32, u32), // filename, width, height
Video { file: String, duration: u32 },
}
fn main() {
let status = Status::Active;
let msg = Message::Text(String::from("Hello!"));
match msg {
Message::Text(content) => println!("Text: {}", content),
Message::Image(file, w, h) => println!("Image: {} ({}x{})", file, w, h),
Message::Video { file, duration } => println!("Video: {} ({}s)", file, duration),
}
}
Compare to C++ enum classes:
enum class Status {
Active,
Inactive,
Pending
};
// C++ doesn't have built-in variant types like this
// You'd need std::variant or unions
Compare to Python:
from enum import Enum
class Status(Enum):
ACTIVE = 1
INACTIVE = 2
PENDING = 3
# Python doesn't have built-in variant types
# You might use inheritance or type annotations
These grouped data types are called struct and the choice types are called enum.
3.2. How can I store collections of items like lists, arrays, or maps?#
Dynamic lists (like Python lists or C++ vectors):
fn main() {
// Create an empty list
let mut numbers = Vec::new();
numbers.push(1);
numbers.push(2);
numbers.push(3);
// Or create with initial values
let fruits = vec!["apple", "banana", "orange"];
// Access items
println!("First fruit: {}", fruits[0]);
// Iterate through items
for fruit in &fruits {
println!("Fruit: {}", fruit);
}
// Get length
println!("We have {} fruits", fruits.len());
}
Compare to Python:
# Python lists
numbers = []
numbers.append(1)
numbers.append(2)
fruits = ["apple", "banana", "orange"]
print(f"First fruit: {fruits[0]}")
for fruit in fruits:
print(f"Fruit: {fruit}")
Compare to C++:
#include <vector>
std::vector<int> numbers;
numbers.push_back(1);
numbers.push_back(2);
std::vector<std::string> fruits = {"apple", "banana", "orange"};
std::cout << "First fruit: " << fruits[0] << std::endl;
for (const auto& fruit : fruits) {
std::cout << "Fruit: " << fruit << std::endl;
}
Key-value pairs (like Python dictionaries or C++ maps):
use std::collections::HashMap;
fn main() {
// Create an empty map
let mut scores = HashMap::new();
scores.insert("Alice", 95);
scores.insert("Bob", 87);
scores.insert("Carol", 92);
// Access values
match scores.get("Alice") {
Some(score) => println!("Alice's score: {}", score),
None => println!("Alice not found"),
}
// Iterate through key-value pairs
for (name, score) in &scores {
println!("{}: {}", name, score);
}
// Check if key exists
if scores.contains_key("Bob") {
println!("Bob is in the scores");
}
}
Compare to Python:
# Python dictionaries
scores = {}
scores["Alice"] = 95
scores["Bob"] = 87
# Or create with initial values
scores = {"Alice": 95, "Bob": 87, "Carol": 92}
print(f"Alice's score: {scores['Alice']}")
for name, score in scores.items():
print(f"{name}: {score}")
Compare to C++:
#include <map>
std::map<std::string, int> scores;
scores["Alice"] = 95;
scores["Bob"] = 87;
// Access with safety check
auto it = scores.find("Alice");
if (it != scores.end()) {
std::cout << "Alice's score: " << it->second << std::endl;
}
for (const auto& pair : scores) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
These dynamic lists are called Vec and the key-value collections are called HashMap.
3.3. How do I handle situations where a value might or might not be present, like nullptr in C++ or None in Python?#
Instead of using null pointers that can cause crashes, this language uses a special type that explicitly represents “something” or “nothing”.
fn find_person(name: &str) -> Option<Person> {
if name == "Alice" {
Some(Person {
name: String::from("Alice"),
age: 30,
email: String::from("alice@example.com"),
})
} else {
None // Person not found
}
}
fn main() {
let result = find_person("Alice");
// Safe way to handle the result
match result {
Some(person) => println!("Found: {}", person.name),
None => println!("Person not found"),
}
// Alternative shorter syntax
if let Some(person) = find_person("Alice") {
println!("Found: {}", person.name);
}
// Get value with default
let person = find_person("Bob").unwrap_or(Person {
name: String::from("Unknown"),
age: 0,
email: String::from(""),
});
}
Compare to C++ (dangerous):
Person* find_person(const std::string& name) {
if (name == "Alice") {
return new Person{"Alice", 30, "alice@example.com"};
}
return nullptr; // Danger: easy to forget to check
}
int main() {
Person* person = find_person("Alice");
if (person != nullptr) { // Must remember to check
std::cout << "Found: " << person->name << std::endl;
delete person; // Must remember to free
}
}
Compare to Python:
def find_person(name):
if name == "Alice":
return Person("Alice", 30, "alice@example.com")
return None # Could cause AttributeError if not checked
person = find_person("Alice")
if person is not None:
print(f"Found: {person.name}")
The compiler forces you to handle both cases (something and nothing). This prevents:
Null pointer crashes
AttributeErrorin PythonSegmentation faults from accessing invalid memory
You cannot accidentally use a “nothing” value without checking first.
This type is called Option enum.