Slices
What is a slice?
A slice is a non-owning view over a contiguous sequence: &[T] for elements of type T, or &str for UTF-8 text. Slices have a length and refer to data owned elsewhere.
In C#: Similar to Span<T>, ReadOnlySpan<T>, or Memory<T>: a view over existing memory, not a copy.
Slice of an array or Vec
let a = [1, 2, 3, 4, 5];
let slice: &[i32] = &a[1..4]; // elements at index 1, 2, 3
println!("{:?}", slice); // [2, 3, 4]In C#: Like array.AsSpan(1, 3) or new ReadOnlySpan<int>(array, 1, 3).
What a slice looks like in memory
A slice is a fat pointer: a pointer to its first element plus a length. It borrows into a buffer someone else owns โ no allocation, no copy:
let v = vec![10, 20, 30, 40];
let s = &v[1..3]; // &[i32], length 2
s (fat pointer) v's heap buffer
โโโโโโโโโโโโ โโโโโโฌโโโโโฌโโโโโฌโโโโโ
โ ptr โโโโโโผโโโโโโ โ 10 โ 20 โ 30 โ 40 โ
โ len = 2 โ โ โโโโโโดโโโโโดโโโโโดโโโโโ
โโโโโโโโโโโโ โโโโโโโโโโโโถ starts at index 1, so s = [20, 30]A &str has the same shape: a pointer plus a byte length. Because the length travels with
the pointer, a slice always knows its own bounds.
In C#: this is exactly Span<T> / ReadOnlySpan<T> โ a (pointer, length) window over
existing memory rather than a freshly allocated array.
Range syntax
..โ range exclusive of end:0..5is 0, 1, 2, 3, 4...=โ range inclusive of end:0..=5is 0, 1, 2, 3, 4, 5.- Omitted start:
..5means from start up to (exclusive) 5. - Omitted end:
2..means from index 2 to end.
let s = String::from("hello");
let slice: &str = &s[0..2]; // "he"
let slice2: &str = &s[..2]; // same
let slice3: &str = &s[2..]; // "llo"&str as string slice
String slices are &str. String literals are &str. Slicing a String with a byte range gives &str (indices must be at char boundaries).
let s = "hello";
let sub: &str = &s[1..4]; // "ell"In C#: Similar to Substring(1, 3) but without allocating a new string; like AsSpan(1, 3) for ReadOnlySpan<char>.
Common pitfalls
- Out-of-range slice ranges panic.
&v[1..99]aborts at runtime. Usev.get(1..99)(โOption<&[T]>) when the range might not fit. &stris indexed by bytes, and slicing across a char boundary panics. A&stris UTF-8, so&s[0..1]on a multi-byte character (e.g. "รฉ", "ไฝ ") panics. Walk characters withs.chars()/s.char_indices(), or uses.get(range)(โOption) for a checked slice.
In C#: string is UTF-16 and Substring indexes by char (and allocates a copy);
Rust's byte indexing into a no-copy slice is faster, but you must respect char boundaries.
Key takeaway
Use &[T] and &str for non-owning views. Ranges use .. (exclusive) or ..= (inclusive). Slices are the main way to pass โa part ofโ an array or string without copying.