More Data Types
In addition to the basic data types, Rust also supports more complex data types such as vectors, slices, strings, and others. These data types allow for more sophisticated data management and manipulation, similar to those found in other programming languages.
Vectors
Vectors are similar to arrays but are dynamically sized. They can grow or shrink
in size as needed. Vectors are created using the Vec<T>
type, where T
is the
type of elements stored in the vector.
fn main() {
// Creating a new empty vector
let mut vector_var: Vec<i32> = Vec::new();
// Adding elements to the vector
vector_var.push(1);
vector_var.push(2);
vector_var.push(3);
println!("Vector: {:?}", vector_var);
println!("Vector length: {}", vector_var.len());
println!("First element: {}", vector_var[0]);
println!("Second element: {}", vector_var[1]);
println!("Third element: {}", vector_var[2]);
println!("Last element: {}", vector_var[vector_var.len() - 1]);
// Similar to arrays, if vector is empty, accessing the last element with
// length - 1 will cause a panic. To avoid that, we can use the `last`
// method with `unwrap_or` to provide a default value.
println!("Last element: {}", vector_var.last().unwrap_or(&-1));
// Removing the last element from the vector
vector_var.pop();
println!("Vector after pop: {:?}", vector_var);
println!("Vector length after pop: {}", vector_var.len());
println!("Last element: {}", vector_var.last().unwrap_or(&-1));
// Removing an element at a specific index
vector_var.remove(0);
println!("Vector after removing index 0: {:?}", vector_var);
println!("Vector length after removing index 0: {}", vector_var.len());
println!("First element after removing index 0: {}", vector_var[0]);
println!("Last element: {}", vector_var.last().unwrap_or(&-1));
}
Vectors can also be created using the vec!
macro:
fn main() {
// Creating a vector using the vec! macro
let vector_var = vec![1, 2, 3, 4, 5];
println!("Vector: {:?}", vector_var);
println!("Vector length: {}", vector_var.len());
println!("First element: {}", vector_var[0]);
println!("Last element: {}", vector_var.last().unwrap_or(&-1));
}
Slices
Slices are a view into a contiguous sequence of elements in a collection, such
as an array or a vector. They do not own the data they point to, which means
they are lightweight and efficient, and are often used to reference a portion of
an array or a vector without taking ownership of the entire collection. Slices
are created using the &[T]
type, where T
is the type of elements in the
slice.
fn main() {
// Creating a slice from an array
let array_var = [1, 2, 3, 4, 5];
// Slice from index 1 to 3
let slice_var: &[i32] = &array_var[1..4];
// Printing the slice and its properties
println!("Slice: {:?}", slice_var);
println!("Slice length: {}", slice_var.len());
println!("First element of slice: {}", slice_var[0]);
println!("Second element of slice: {}", slice_var[1]);
println!("Third element of slice: {}", slice_var[2]);
println!("Last element of slice: {}", slice_var[slice_var.len() - 1]);
// If slice is empty, accessing the last element with length - 1 will cause
// a panic, similar to arrays and vectors. To avoid that, we can use the
// `last` method with `unwrap_or` to provide a default value.
println!("Last element of slice: {}", slice_var.last().unwrap_or(&-1));
}
fn main() {
// Creating a slice from a vector
let vector_var = vec![1, 2, 3, 4, 5];
// Slice from index 1 to 3
let slice_var: &[i32] = &vector_var[1..4];
// Printing the slice and its properties
println!("Slice: {:?}", slice_var);
println!("Slice length: {}", slice_var.len());
println!("First element of slice: {}", slice_var[0]);
println!("Second element of slice: {}", slice_var[1]);
println!("Third element of slice: {}", slice_var[2]);
println!("Last element of slice: {}", slice_var.last().unwrap_or(&-1));
}
Strings
Strings in Rust are represented by the String
type, which is a growable,
heap-allocated data structure. Strings are UTF-8 encoded, allowing for a wide
range of characters. Strings can be created using the String::new()
function,
the String::from()
function, or by converting a string literal using the
to_string()
method.
fn main() {
// Creating a new empty String
let mut s1 = String::new();
// Creating a String from a string literal
let s2 = String::from("Hello, Rust!");
// Converting a string literal to a String
let s3 = "Hello, Rust!".to_string();
// Appending to a String
s1.push_str("Hello");
s1.push(',');
s1.push(' ');
s1.push_str("Rust!");
// Printing the Strings
println!("s1: {}", s1);
println!("s2: {}", s2);
println!("s3: {}", s3);
}
Another way to handle strings is through string slices, which are references to
a portion of a string. String slices are denoted by the &str
type and are
commonly used for string literals.
fn main() {
// String slice from a string literal
let str_slice: &str = "Hello, Rust!";
println!("String slice: {}", str_slice);
}
The difference between String
and &str
is that String
is a growable,
heap-allocated data structure, while &str
is a reference to a string slice,
which is usually immutable and points to a specific portion of a string. A more
detailed difference is that String
is an owned type, meaning it has ownership
of the string data and is responsible for managing its memory. On the other
hand, &str
is a borrowed type, meaning it references string data owned by
another variable.
More about ownership and borrowing will be covered later.