String Slices: &str
fn first_word(s: &str) -> &str {
for (i, c) in s.char_indices() {
if c == ' ' { return &s[..i]; }
}
s // Whole string if no space
}
fn main() {
let s = String::from("hello world");
let word = first_word(&s);
println!("First word: {}", word);
// s.clear(); // Would ERROR if word is still used after
// String literals are &str (pointing to binary):
let lit: &str = "hello";
// &String coerces to &str:
let owned = String::from("owned");
let slice: &str = &owned;
// Prefer &str in function parameters:
fn print_str(s: &str) { println!("{}", s); }
print_str(lit); // &str - fine
print_str(&owned); // &String -> &str coercion
// Slice ranges
let s = "hello world";
println!("{}", &s[0..5]); // "hello"
println!("{}", &s[6..]); // "world"
}Array and General Slices
fn sum(slice: &[i32]) -> i32 {
slice.iter().sum()
}
fn main() {
let arr = [1, 2, 3, 4, 5];
let v = vec![10, 20, 30, 40, 50];
println!("{}", sum(&arr)); // Array slice
println!("{}", sum(&v)); // Vec slice
println!("{}", sum(&v[1..4])); // Partial slice [20,30,40]
// Slice methods
let slice = &arr[1..4]; // [2, 3, 4]
println!("len: {}", slice.len());
println!("first: {:?}", slice.first());
println!("last: {:?}", slice.last());
println!("contains 3: {}", slice.contains(&3));
// Sort a mutable slice
let mut data = [5, 2, 8, 1, 9, 3];
data.sort();
println!("{:?}", data);
// Split at
let (left, right) = data.split_at(3);
println!("left: {:?} right: {:?}", left, right);
}🎯 Practice
- Write fn max_slice(s: &[f64]) -> Option<f64> returning the max element
- Write fn is_sorted(s: &[i32]) -> bool checking if slice is non-decreasing
- Write fn words(s: &str) -> Vec<&str> splitting on whitespace (return slices)
🎉 Key Takeaways
- Slices borrow a contiguous sequence without owning the data
- &str is a string slice; prefer it over &String in function params
- String literals are &'static str stored in the binary
- &[T] is a general slice; works with arrays and Vecs