Idiomatic way of handling pointers to slices

One of the things I am having difficulties in Rust is handling pointers, more specifically their usage in slices/vectors.

In C, it's possible to have a pointer to an array and make it easy to grab the first element or even increment that pointer to get the next elements inside that array.

int test_array[5] = {1, 2, 3, 10, 100};
int *p;

printing *p would give us the first element.

Now in rust, there are multiple ways in which this example can be done.

let slice: [i32;5] = [1,2,3,10,100];
    unsafe{let p = slice.as_ptr();
        println!("{}",*p);
    }

this can also be done by Rc, Box depending on the mutability and ownership of course.
there is also .first() which returns the first element. However, i am unsure about its safety and that doesn't work with incrementing.

My question is what's the idiomatic way to handle slices elements using pointers safely? How would the C example be written Rust while insuring safety?

The main tools you may want here are things like .split_first{,_mut}:

let array: [i32; 5] = [1,2,3,10,100];
let mut slice_ref: &[i32] = &array[..];
while let Some((element_ref, remaining)) = slice_ref.split_first() {
    println!("{}", *element_ref);
    slice_ref = remaining;
}

There is also .split_at{,_mut}(idx) for a generalization of this pattern.

And this while let Some... pattern can be factored out thanks to the Iterator abstraction, which does exactly that under the hood, while hiding the nitty-gritty details:

for element_ref in &slice[..] { /* pointer is magically auto-incremented as needed */
    println!("{}", *element_ref);
}

(The idea is that rather than using raw increment operators, which are dangerous because they could go out of bounds, one using .increment()-like methods that check these things :slightly_smiling_face:)

4 Likes