How to just continue if an array index is out of range? - rust

Let's say that I have this array - [1, 2, 3, 4, 5] - and I try to access an index that doesn't exist (Let's say 6). It would normally through an error. But is there any way that I can just completely ignore that error and continue like nothing happened?

Arrays ([T; N] with a fixed size N known at compile time) can be freely coerced into slices ([T] with a variable length known at runtime), so when you have an array you have access to the wide array of slice methods.
For your use case, slice::get returns an Option<T>. If the index is valid you get Some(value), and if it's invalid you get None.
Example:
let array = [1, 2, 3, 4, 5];
let index = 6;
if let Some(value) = array.get(index) {
println!("Found {} at array[{}]", value, index);
}
else {
println!("array[{}] is out of bounds", index);
}
Output:
array[6] is out of bounds
Playground

If the array index is negative, you will get a compile time error because it have to be of type usize.
If its positive, you could compare it with the length of the array.
To handle an out of bounds index (like 6 in this case), you could do something like:
fn get_item(input_array: &[i8; 5], index: usize) -> i8 {
if index >= input_array.len() {
-1
} else { // continue
input_array[index]
}
}
#[test]
fn test_get_item() {
assert_eq!(get_item(&[1, 2, 3, 4, 5], 2), 3, "Value at index 2 is 3");
}
#[test]
fn test_get_item_out_of_bounds() {
assert_eq!(
get_item(&[1, 2, 3, 4, 5], 6),
-1,
"Array index out of bounds"
);
}

Related

Rust: Creating a slice from a reference

Is it possible to create a slice of an array (or anything else) using references into that array to specify the start/end rather than indices?
For example, say I am iterating through an array, and when I get to a certain element I want to call a function passing a slice of the array from the current element to the end:
let list = [1, 2, 3, 4, 5, 6];
for item in &list {
if passes_test(item) {
process_remainder(&list[item..]); // does not compile
}
}
Coming from C this seems like a natural thing to want to do - a reference is just a pointer, and a slice is just a pair of pointers (or pointer and length), and taking multiple references should be fine since none of them are mutable. But I can't find right syntax to do it.
Alternately, is it possible to get the index for a given reference (like with pointer arithmetic in C), or do I just need to break down and use enumerate to generate both index and reference as I iterate?
Usually, enumerate is preferred over pointer arithmetic.
fn main() {
let list = [1i32, 2, 3, 4, 5, 6];
for (index, item) in list.iter().enumerate() {
if *item > 5 {
process_remainder(&list[index..]);
}
}
}
(Accidentally, your code does compile since array items are usize. :) So I changed them to i32.)
You can do it, but it's neither safe nor pretty:
let list = [1, 2, 3, 4, 5, 6];
for item in &list {
if passes_test(item) {
let idx = unsafe { (item as *const u64).offset_from(list.as_ptr()) as usize };
process_remainder(&list[idx..]);
}
}
Using enumerate is a better option:
let list = [1, 2, 3, 4, 5, 6];
for (i, item) in list.iter().enumerate() {
if passes_test(item) {
process_remainder(&list[i..]);
}
}

Implementing PHP array_column in Rust

I'm in the process of learning Rust, but I could not find an answer to this question.
In PHP, there's the array_column method and it works this way:
given an array of arrays (this would be a a Vector of vectors in Rust):
$records = [
[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3]
];
if I want to get an array containing all the first elements (a "column") of the inner arrays I can do:
$column = array_column($records, 0);
This way, for example, I get [1,1,1,1]. If I change that 0 with 1, I get [2,2,2,2] and so on.
Since there's no array_column equivalent in Rust (that is: I could not find it), what could be the best way to implement a similar behavior with a vector of vectors?
I decided to play with iterators, as you tried in the comments.
This version works with any clonable values (numbers included). We iterate over subvectors, and for each we call a get method, which either yields an element of the vector Some(&e) or None if we ask out of bounds.
and_then then accepts a value from get, and if it was None, then None is returned, otherwise, if it's Some(&e) then Some(e.clone()) is returned, i.e. we clone the value (because we only have the reference to the value from get, we can't store it, we have to copy the value).
collect then works with Iter<Option<T>>, and it conveniently turns it in Option<Vec<T>>, i.e. it returns None if some Nones were in the iterator (which means some arrays didn't have big enough size), or returns Some(Vec<T>), if everything is fine.
fn main() {
let array = vec![
vec![1, 2, 3, 4],
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4],
vec![1, 2, 3, 4],
];
let ac = array_column(&array, 0);
println!("{:?}", ac); // Some([1, 1, 1, 1])
let ac = array_column(&array, 3);
println!("{:?}", ac); // Some([4, 4, 4, 4])
let ac = array_column(&array, 4); // None
println!("{:?}", ac);
}
fn array_column<T: Clone>(array: &Vec<Vec<T>>, column: usize) -> Option<Vec<T>> {
array.iter()
.map( |subvec| subvec.get(column).and_then(|e| Some(e.clone())) )
.collect()
}
Alex version is good, but you can generalize it using references too, so there will be no need for the item to be Clone:
fn array_column<'a, T>(array: &'a Vec<Vec<T>>, column: usize) -> Option<Vec<&'a T>> {
array.iter()
.map( |subvec| subvec.get(column) )
.collect()
}
Playground

How to get the minimum value within a vector in Rust?

I'm trying to display the minimum value within a vector in Rust and can't find a good way to do so.
Given a vector of i32 :
let mut v = vec![5, 6, 8, 4, 2, 7];
My goal here is to get the minimum value of that vector without having to sort it.
What is the best way to get the minimum value within a Vec<i32> in Rust ?
let minValue = vec.iter().min();
match minValue {
Some(min) => println!( "Min value: {}", min ),
None => println!( "Vector is empty" ),
}
https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min
fn min(self) -> Option<Self::Item>
where
Self::Item: Ord,
Returns the minimum element of an iterator.
If several elements are equally minimum, the first element is returned. If the iterator is empty, None is returned.
I found this Gist which has some common C#/.NET Linq operations expressed in Swift and Rust, which is handy: https://gist.github.com/leonardo-m/6e9315a57fe9caa893472c2935e9d589
let mut v = vec![5, 6, 8, 4, 2, 7];
let minValue = *v.iter().min().unwrap();
Hi #octano As Dai has already answered, min/max return Option<> value, so you can only match it as in example:
fn main() {
let vec_to_check = vec![5, 6, 8, 4, 2, 7];
let min_value = vec_to_check.iter().min();
match min_value {
None => println!("Min value was not found"),
Some(i) => println!("Min Value = {}", i)
}
}
Play ground example for Iter.min()

Assigning values in a 2D array

I'm writing some code in Rust (mainly as a POC). The code takes a 2D array, passes it to a second function to do some matrix math (I know there is a standard library to do this, but I want to get used to how things work).
The problem is that the assignment to a 2D array is causing an issue.
My code looks like this
fn main()
{
// first create a couple of arrays - these will be used
// for the vectors
let line1: [i32; 4] = [4, 2, 3, 3];
let line2: [i32; 4] = [3, 4, 5, 7];
let line3: [i32; 4] = [2, 9, 6, 2];
let line4: [i32; 4] = [5, 7, 2, 4];
// create two holding arrays and assign
let array_one = [line1, line3, line4, line2];
let array_two = [line2, line1, line3, line4];
// let's do the multiply
let result = matrix_multiply(&array_one, &array_two);
println!("{:?}", result);
}
fn matrix_multiply(vec1:&[&[i32;4];4], vec2:&[&[i32;4];4]) -> [[i32; 4];4]
{
// we need to deference the parameters passed in
let vec_one:[[i32;4];4] = vec1;
let vec_two:[[i32;4];4] = vec2;
// we need to store the sum
let mut sum = 0;
// we need to create the arrays to put the results into
let mut result = [[0i32; 4]; 4];
// loop through the two vectors
for vone in 0..4
{
for vtwo in 0..4
{
for k in 0..4
{
sum = sum + vec1[[vone].k] * vec2[[k].vtwo];
}
result[[vec_one].vec_two] = sum;
sum = 0;
}
}
return result;
}
I've also tried result[vec_one][vec_two] = sum but when I come to compile, it looks like there is a problem assigning to array.
What am I doing wrong here?
Here is your error, I believe (at least one of them):
<anon>:15:34: 15:44 error: mismatched types:
expected `&[&[i32; 4]; 4]`,
found `&[[i32; 4]; 4]`
(expected &-ptr,
found array of 4 elements) [E0308]
<anon>:15 let result = matrix_multiply(&array_one, &array_two);
^~~~~~~~~~
The problem is, reference or dereference of arrays can't go on multiple levels of their nesting. This is because the memory layout of, say, [&[i32; 4]; 4] and [[i32; 4]; 4] is radically different, both in contents and in size - the former array consists of four pointers to other arrays (4*4=16/8*4=32 bytes total, depending on architecture of your machine), while the latter consists of four arrays laid out sequentially (4*4*4=64 bytes total). There is simply no way to go from [[i32; 4]; 4] to &[&[i32; 4]; 4] without rebuilding the outer array, which Rust won't ever do for you because it is too much magic.
You don't really need to use the inner reference; in fact, you probably don't even need to pass these arrays by reference at all: arrays of Copy types are Copy as well, so you can pass them by value. They are small enough to not cause any performance impact, and the compiler will probably optimize it automatically anyway:
fn main() {
// first create a couple of arrays - these will be used
// for the vectors
let line1: [i32; 4] = [4, 2, 3, 3];
let line2: [i32; 4] = [3, 4, 5, 7];
let line3: [i32; 4] = [2, 9, 6, 2];
let line4: [i32; 4] = [5, 7, 2, 4];
// create two holding arrays and assign
let array_one = [line1, line3, line4, line2];
let array_two = [line2, line1, line3, line4];
// let's do the multiply
let result = matrix_multiply(array_one, array_two);
println!("{:?}", result);
}
fn matrix_multiply(vec1: [[i32; 4]; 4], vec2: [[i32; 4]; 4]) -> [[i32; 4]; 4] {
// we need to create the arrays to put the results into
let mut result = [[0i32; 4]; 4];
// loop through the two vectors
for vone in 0..4 {
for vtwo in 0..4 {
let mut sum = 0;
for k in 0..4 {
sum += vec1[vone][k] * vec2[k][vtwo];
}
result[vone][vtwo] = sum;
}
}
result
}
(try it here)
I've also made your code more idiomatic according to the current community practices (braces positioning, spacing, etc.), and I've fixed the weird syntax for accessing arrays.
If you write
let line1: [i32; 4] = [4, 2, 3, 3];
let line2: [i32; 4] = [3, 4, 5, 7];
let line3: [i32; 4] = [2, 9, 6, 2];
let line4: [i32; 4] = [5, 7, 2, 4];
// create two holding arrays and assign
let array_one = [line1, line3, line4, line2];
the type of array_one will be [[i32;4];4] because the line arrays are copied into array_one. Borrowing this via &array_one gives you something of type &[[i32;4];4] which is very different from &[&[T; 4]; 4] (what the function you try to call expects).
Option1 -- Create [&[T; 4]; 4]:
let array_one = [&line1, &line3, &line4, &line2];
some_function(&array_one);
...
fn some_function(matrix: &[&[i32;4];4]) {...}
Option2 -- Change the function sitnature:
let array_one = [line1, line3, line4, line2];
some_function(&array_one);
...
fn some_function(matrix: &[[i32;4];4]) {...}
If you're interested in dealing with multi-dimensional arrays of arbitrary sizes, perhaps you'll find my experimental multiarray crate useful. It basically tries to offer types similar to Box<[T]>, &[T] and &mut[T] for two or more dimensions. Here's an untested example just to get an idea of what I was trying to do:
extern crate multiarray;
use multiarray::*;
fn main() {
// the backing memory will be a dynamically allocated
// linear array with 4 elements in row-major (C-style) order.
let mut matrix = Array2D::new([2, 2], 0i32);
matrix[[0,0]] = 1; matrix[[0,1]] = 2;
matrix[[1,0]] = 3; matrix[[1,1]] = 4;
let mut square = Array2D::new([2, 2], 0i32);
// the borrow methods create reference-like proxies
mat_product(matrix.borrow(), matrix.borrow(),
square.borrow_mut());
}
fn mat_product(a: Array2DRef<i32>, b: Array2DRef<i32>,
mut c: Array2DRefMut<i32>) {
let rows = a.extents()[0]; // extent of 1st dimension
let intr = a.extents()[1]; // extent of 2nd dimension
let cols = b.extents()[1]; // extent of 2nd dimension
assert!(intr == b.extents()[0]);
assert!(rows == c.extents()[0]);
assert!(cols == c.extents()[1]);
for i in 0..rows {
// the i-th row of a and c...
let a_row_i = a.eliminated_dim(0, i);
let mut c_row_i = c.reborrow_mut().eliminated_dim(0, i);
for j in 0..cols {
c_row_i[j] = dot_product(a_row_i, b.eliminated_dim(1, j));
// ^^^j-th column of b^^^
}
}
}
fn dot_product(a: Array1DRef<i32>, b: Array1DRef<i32>) -> i32 {
a.zip(b).fold(0, |acc,(&x,&y)| acc + x * y)
}

"borrowed value does not live long enough" when using a struct with a slice

Editor's note: The code in this question predates Rust 1.0. Since then, semantics have changed and some of the assertions made in the question are no longer true.
I have the following piece of code:
extern crate debug;
use std::mem::size_of_val;
struct A<'a> {
a: &'a [i64],
}
fn main() {
// code
}
When I define a slice with & (i.e. &[1, 2, 3]) as in the following println!
println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] });
the output is
16 - A<'static>{a: &[1i64, 2i64, 3i64]}
Defining a slice without &
println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] });
gives me the same result
16 - A<'static>{a: &[1i64, 2i64, 3i64]}
If I first try to bind an instance of a struct A, whose a field is initialized with a reference to a slice (i.e. using &), to a variable x
let x = A { a: &[1, 2, 3] }; // &[1, 2, 3] is a reference to a slice
and I try to execute a similar println! as the previous ones
println!("{} - {:?}", size_of_val(&x), x);
I get
16 - A<'static>{a: &[1i64, 2i64, 3i64]}
However, if I bind an instance of A, whose a field is initialized to a slice (not a reference to a slice using &), to a variable x
let x = A { a: [1, 2, 3] };
and I try to execute a similar println! as the previous ones
println!("{} - {:?}", size_of_val(&x), x);
I get the following build error:
/prpath/main.rs:12:20: 12:29 error: borrowed value does not live long enough
/prpath/main.rs:12 let x = A { a: [1 ,2, 3] };
^~~~~~~~~
/prpath/main.rs:11:11: 15:2 note: reference must be valid for the block at 11:10...
/prpath/main.rs:11 fn main() {
/prpath/main.rs:12 let x = A { a: [1 ,2, 3] };
/prpath/main.rs:13
/prpath/main.rs:14 println!("{} - `{:?}`", size_of_val(&x), x);
/prpath/main.rs:15 }
/prpath/main.rs:12:5: 12:31 note: ...but borrowed value is only valid for the statement at 12:4; consider using a `let` binding to increase its lifetime
/prpath/main.rs:12 let x = A { a: [1 ,2, 3] };
^~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
I was expecting that only the A { a: &[1, 2, 3] } definition was allowed because A.a should have &[i64] type, but, apparently, Rust allows us to not include an & symbol.
What is the difference between A { a: &[1, 2, 3] } and A { a: [1, 2, 3] }? Why are we allowed to use A { a: [1, 2, 3] } (in the second example above)?
First, you can use a [T,..n] where a &[T] is expected, the conversion to a slice is implicit. So following code is perfectly valid:
let a = [1u, 2, 3];
let b: &[uint] = a;
Your situation is a purely lifetime problem. Your struct is
struct A<'a> {
a: &'a [i64],
}
It holds a slice. A slice is nothing more than a reference to the first element and a count of the number of elements. That's why size_of_val() called on a A will always return 16: it's the size of a slice, one u64 for the pointer, and one u64 for the number of elements (as you seems to be on a 64bits computer).
So in your code, the struct does not own the array. The difference in behavior you observe is due to the difference about when the array does out of scope.
First case:
let x = A { a: [1, 2, 3] };
Here you define an array, and stores a slice to this array in your struct. Then when reaching the ;, your array does out of scope and is destroyed, and thus the reference in x is not valid anymore: it is forbidden by the compiler.
Second case:
let x = A { a: &[1, 2, 3] };
It is more peculiar. Your array is stored in an anonymous variable. In fact, writing
let foo = &42u;
is equivalent to writing
let _anonymousvariable = 42u;
let foo = &_anonymousvariable;
Except that you can't reach _anonymousvariable directly.
It's exactly the same for you, your code is equivalent to
let _anonymous_array = [1, 2, 3]
let x = A { a: &_anonymous_array };
and thus is perfectly valid.
Last case:
When you write everything directly in the println!(). Thanks to previous case, we now see why this works:
println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] });
but in this case there is no problem either:
println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] });
because your arrays only go out of scope when reaching the ;, and no reference to them exist past this point, so they can be safely deleted and the compiler is happy.

Resources