Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Special pages
JOHNWICK
Search
Search
Appearance
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Slices
Page
Discussion
English
Read
Edit
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
View history
General
What links here
Related changes
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
Yesterday we checked out Loops in-depth and other niceties around them, if you missed it, I’d recommend checking it out below. Loops Loops in programming (fundamental and very useful), including Rust, are like a repeating task you tell the computer to… medium.com In this post, let’s discuss Slices, it’s day 19 here we go! A slice in Rust is like a window into a portion of a sequence, such as an array, vector, or string. It’s a reference to a contiguous chunk of data, letting you work with just that part without taking ownership or copying anything. Think of it as borrowing a few pages from a book instead of buying the whole book or photocopying it. This makes slices memory-efficient and fast, which is critical in performance-sensitive applications like game development or data processing. Slices come in two main flavors: array/vector slices (&[T]) and string slices (&str). Both are references, meaning they don’t own the data they point to, and they’re defined by a starting point and a length. For example, if you have an array of numbers, a slice might let you focus on just the first three elements without touching the rest. Below is a simple example to get us started. Imagine you’re building a log parser for a web server, and you need to process the first few entries of a large log stored in a vector: <pre> fn main() { let logs = vec!["GET /home", "POST /login", "GET /profile", "PUT /settings"]; let recent_logs = &logs[0..2]; // Slice of the first two entries println!("Recent logs: {:?}", recent_logs); // Prints: ["GET /home", "POST /login"] } </pre> In the above code, recent_logs is a slice (&[&str]) that references just the first two elements of the logs vector. No copying happens, and Rust’s borrow checker ensures you don’t accidentally modify the original vector if you’re only borrowing it. Let’s move on to how slices are created and used in more complex scenarios, like those you’d encounter in a real project. Creating and Using Slices Slices are created using the .. range syntax, which specifies the start and end indices of the portion you want. The syntax is flexible: you can write 0..2 for the first two elements, 1.. to start at index 1 and go to the end, or even ..3 to start from the beginning up to index 2. This flexibility is handy when you’re dealing with dynamic data. Suppose you’re working on a music streaming app, and you need to display a subset of songs from a playlist based on user input. The playlist is stored as a vector, and the user wants to see songs 3 through 5. Here’s how you might handle it: <pre> fn get_playlist_slice(playlist: &[String], start: usize, end: usize) -> &[String] { &playlist[start..end] } fn main() { let playlist = vec![ String::from("Song A"), String::from("Song B"), String::from("Song C"), String::from("Song D"), String::from("Song E"), ]; let user_selection = get_playlist_slice(&playlist, 2, 5); println!("User's selection: {:?}", user_selection); // Prints: ["Song C", "Song D", "Song E"] } </pre> This function above takes a slice of the playlist as input (so it works with vectors or arrays) and returns a slice of the requested range. Notice how we pass &playlist to avoid moving the vector, and the function returns a slice (&[String]) that borrows the data. This is a common pattern in Rust: functions that process data often take slices as arguments to be flexible and avoid ownership issues. String slices (&str) work similarly but are suited for text. Let’s say you’re parsing a CSV file for a data analytics tool, and you need to extract the header row’s first column. The CSV is stored as a string, and you want just the part before the first comma: <pre> fn get_first_column(csv: &str) -> &str { csv.split(',').next().unwrap_or("") } fn main() { let csv_data = "name,age,city\nAlice,30,New York"; let first_column = get_first_column(csv_data); println!("First column: {}", first_column); // Prints: "name" } </pre> In the code above, get_first_column returns a &str slice of the input string, pointing to the substring before the first comma. Since it’s a slice, there’s no allocation or copying, just a reference to the original string’s data. Now that we’ve seen how to create and use slices, let’s look at some real-world scenarios where they’re particularly useful. Real-World Scenarios for Slices Slices shine in situations where you need to process parts of data efficiently. Here are a few practical examples inspired by real-world tasks: 1. Filtering Log Data in a Monitoring System Imagine you’re building a monitoring system for a cloud service, and you need to analyze recent error logs from a massive log array. You only want errors from the last hour, which correspond to the last 100 entries. Slices make this easy: <pre> fn get_recent_errors(logs: &[String], count: usize) -> &[String] { let start = logs.len().saturating_sub(count); &logs[start..] } fn main() { let logs = vec![ String::from("INFO: Server started"), String::from("ERROR: Connection failed"), String::from("ERROR: Timeout"), String::from("INFO: Request processed"), ]; let recent_errors = get_recent_errors(&logs, 2); println!("Recent errors: {:?}", recent_errors); // Prints: ["ERROR: Connection failed", "ERROR: Timeout"] } </pre> The saturating_sub method ensures we don’t underflow if the log is shorter than count, and the slice &logs[start..] gives us the last two entries efficiently. 2. Processing Image Data in a Graphics Editor In a graphics editor, you might need to apply a filter to a specific region of an image, represented as a 1D array of pixels. Slices let you focus on just the region of interest: <pre> fn apply_grayscale(pixels: &mut [u8], start: usize, end: usize) { for pixel in pixels[start..end].iter_mut() { *pixel = (*pixel as u32 * 3 / 10) as u8; // Simple grayscale conversion } } fn main() { let mut image_data = vec![255, 128, 64, 192, 32]; apply_grayscale(&mut image_data, 1, 4); println!("Processed pixels: {:?}", image_data); // Prints: [255, 38, 19, 57, 32] } </pre> Here, the slice &mut image_data[1..4] lets us modify a specific range of pixels without affecting the rest of the image. 3. Parsing API Responses When working with JSON responses in a web app, you might need to extract a specific field from a string. For example, suppose an API returns a JSON string, and you want to grab the value of a "user_id" field. String slices can help you avoid unnecessary allocations: <pre> fn extract_user_id(json: &str) -> Option<&str> { json.find("\"user_id\":") .map(|start| { let value_start = start + "\"user_id\":".len(); let value_end = json[value_start..].find(',').map(|i| i + value_start).unwrap_or(json.len()); json[value_start..value_end].trim() }) } fn main() { let json_response = r#"{"user_id": "12345", "name": "Alice"}"#; if let Some(user_id) = extract_user_id(json_response) { println!("User ID: {}", user_id); // Prints: "12345" } } </pre> This function uses string slices to extract the user_id value without copying the string, keeping memory usage low. These examples we have seen above show how slices fit naturally into tasks like log analysis, image processing, and API parsing. Next, let’s talk about some common pitfalls and how to avoid them. Avoiding Common Pitfalls Slices are powerful, but Rust’s strict borrow checker can trip you up if you’re not careful. Here are some issues you might hit in real projects and how to handle them: 1. Lifetime Issues Since slices are references, they’re tied to the lifetime of the data they point to. If the underlying data (like a vector) is dropped, the slice becomes invalid. For example: <pre> fn bad_slice() -> &[i32] { let numbers = vec![1, 2, 3]; &numbers[0..2] // Error: `numbers` doesn't live long enough } </pre> The code above won’t compile because the vector numbers is dropped when the function ends, but the slice tries to reference it. To fix this, ensure the data outlives the slice, perhaps by returning the vector along with the slice or using a static lifetime. 2. Index Out of Bounds Accessing a slice with invalid indices causes a panic. Imagine you’re slicing user input data, and the user provides bad indices: <pre> fn safe_slice(data: &[i32], start: usize, end: usize) -> Option<&[i32]> { if start <= end && end <= data.len() { Some(&data[start..end]) } else { None } } fn main() { let numbers = vec![1, 2, 3, 4]; match safe_slice(&numbers, 2, 5) { Some(slice) => println!("Slice: {:?}", slice), None => println!("Invalid range"), } // Prints: "Invalid range" } </pre> By checking the indices, you avoid panics and make your code more reliable, especially in user-facing applications. 3. Mutable vs. Immutable Borrowing Rust enforces that you can’t have a mutable and immutable borrow of the same data at the same time. This can bite you when working with mutable slices: <pre> fn main() { let mut data = vec![1, 2, 3]; let slice1 = &data[0..2]; let slice2 = &mut data[1..3]; // Error: cannot borrow `data` mutably println!("{:?}, {:?}", slice1, slice2); } </pre> To fix this, always ensure mutable slices don’t overlap with other borrows, or use separate scopes to limit borrow lifetimes. That was all on slices Read the full article here: https://medium.com/rustaceans/slices-c43e8a33d0bc
Summary:
Please note that all contributions to JOHNWICK may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
JOHNWICK:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Search
Search
Editing
Slices
Add topic