Day 13c: Iteration, Borrowing, and Slicing Vectors in Rust

Venkat Annangi
Venkat Annangi
01/10/2024 04:19 4 min read 36 views
#rust-vectors #rust #108 days of rust

Day 13c: Iteration, Borrowing, and Slicing Vectors in Rust

Welcome to Day 12c! Today, we’ll explore three key features of vectors: iteration, borrowing, and slicing. These concepts are critical for effectively working with vectors in Rust, allowing you to access and manipulate data in efficient ways.

1. Iterating Over Vectors

Iteration is a common operation when working with collections like vectors. Rust provides multiple ways to iterate over vector elements, each with its own use case.

a. Using a for Loop

The simplest way to iterate over a vector is to use a for loop. This allows you to access each element in the vector in sequence.

Example:

fn main() {
    let scores = vec![85, 90, 78, 92];

    for score in &scores {
        println!("Score: {}", score);
    }
  }

In this example, the for loop iterates over each element in scores. The &scores reference ensures that we do not take ownership of the vector.

b. Using .iter() for Immutable Access

The iter() method returns an iterator over the vector, allowing you to access elements immutably.

Example:

fn main() {
    let values = vec![1, 2, 3, 4, 5];

    for value in values.iter() {
        println!("Value: {}", value);
    }
  }

The iter() method is commonly used when you want to read each element without modifying it.

c. Using .iter_mut() for Mutable Access

The iter_mut() method returns a mutable iterator, allowing you to modify the elements of the vector.

Example:

fn main() {
    let mut data = vec![10, 20, 30];

    for value in data.iter_mut() {
        *value += 5; // Modify each element by adding 5
    }

    println!("Modified data: {:?}", data);
  }

Using iter_mut(), you can safely modify each element in the vector without moving ownership.

2. Borrowing Vectors

Borrowing is a fundamental concept in Rust, allowing you to use references to access data without taking ownership. You can borrow vectors immutably or mutably, depending on the use case.

a. Immutable Borrowing

An immutable reference (&) allows you to access a vector without modifying it. This is useful when multiple parts of your code need to read the vector simultaneously.

Example:

fn main() {
    let fruits = vec!["apple", "banana", "cherry"];
    let borrowed_fruits = &fruits;

    println!("Borrowed fruits: {:?}", borrowed_fruits);
  }

b. Mutable Borrowing

A mutable reference (&mut) allows you to modify the vector. Only one mutable reference can exist at a time to prevent data races.

Example:

fn main() {
    let mut numbers = vec![1, 2, 3];
    let borrowed_numbers = &mut numbers;

    borrowed_numbers.push(4); // Add an element through the mutable reference
    println!("Updated numbers: {:?}", numbers);
  }

In this example, we use &mut to borrow the vector mutably and add an element to it.

3. Slicing Vectors

A slice is a reference to a contiguous segment of a vector. Slices allow you to work with a part of a vector without needing to copy data, and they are an important tool for efficient memory usage.

a. Creating a Slice

You can create a slice by specifying a range of indices within the vector.

Example:

fn main() {
    let data = vec![10, 20, 30, 40, 50];
    let slice = &data[1..4]; // Slice containing elements from index 1 to 3

    println!("Slice: {:?}", slice);
  }

In this example, &data[1..4] creates a slice with the elements [20, 30, 40]. The range is inclusive of the start index (1) and exclusive of the end index (4).

b. Passing Slices to Functions

Slices are often used as function parameters to avoid passing the entire vector and to ensure that functions do not take ownership of the data.

Example:

fn main() {
    let values = vec![5, 10, 15, 20];
    print_slice(&values[1..3]);
}

fn print_slice(slice: &[i32]) {
    println!("Slice: {:?}", slice);
}

In this example, the function print_slice takes a slice as its parameter, allowing it to access part of the vector without ownership.

Conclusion

Iteration, borrowing, and slicing are key techniques for efficiently working with vectors in Rust. Iterators allow you to access elements in a controlled manner, borrowing enables multiple parts of your code to access data safely, and slicing provides a way to work with portions of a vector without copying data. By understanding and using these techniques, you can write more performant and flexible Rust code.

In the next post, Day 13d, we’ll cover advanced operations on vectors, including capacity management and common use cases, giving you even more control over how you use this versatile data structure.

Comments