Datatype for indexing vector - rust

I just started to learn Rust. I understand that Rust's for loop indices and vector indices must be of type usize, hence I have written the following code. The computation of j within the for loop requires i to be type u32, so I convert it. Now, I have to change the type of i and j again to get the vector items.
I would like to avoid this constant back-and-forth conversion, is there an alternate way to do this in Rust? Thank you for your help.
fn compute(dots: Vec, N: u32) -> f32 {
let mut j: u32;
let mut value: f32 = 0.0;
for i in 0..N {
j = (i as u32 + 1) % N;
value += dots[i as usize].a * dots[j as usize].b;
value -= dots[i as usize].b * dots[j as usize].a;
}
return value
}

Either change the function signature to use N: usize, or, if you can't do that, just let M = N as usize and loop over 0..M (the loop variable will then have type usize).
Be aware that in real code, you need to be sure that usize is at least as wide as u32 if you opt for the conversion. If you cannot assure that, use try_into instead of as to convert.

Related

How to sum a slice of bytes reducing the possibility of overflow

I have an ASCII string slice and I need to compute the sum of all characters when seen as bytes.
let word = "Hello, World";
let sum = word.as_bytes().iter().sum::<u8>();
I need to specify the type for sum, otherwise Rust will not compile. The problem is that u8 is a too small type, and if the sum overflows the program will panic.
I'd like to avoid that, but I cannot find a way to specify a bigger type such as u16 or u32 for example, when using sum().
I may try to use fold(), but I was wondering if there is a way to use sum() by specifying another type.
let sum = word.as_bytes().iter().fold(0u32, |acc, x| acc + *x as u32);
You can use map to cast each byte to a bigger type:
let sum: u32 = word.as_bytes().iter().map(|&b| b as u32).sum();
or
let sum: u32 = word.as_bytes().iter().cloned().map(u32::from).sum();
The reason why you can't sum to u32 using your original attempt is that the Sum trait which provides it has the following definition:
pub trait Sum<A = Self> {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = A>;
}
Which means that its method sum returns by default the same type as the items of the iterator it is built from. You can see it's the case with u8 by looking at its implementation of Sum:
fn sum<I>(iter: I) -> u8
where
I: Iterator<Item = u8>,

How to translate "x-y" to vec![x, x+1, … y-1, y]?

This solution seems rather inelegant:
fn parse_range(&self, string_value: &str) -> Vec<u8> {
let values: Vec<u8> = string_value
.splitn(2, "-")
.map(|part| part.parse().ok().unwrap())
.collect();
{ values[0]..(values[1] + 1) }.collect()
}
Since splitn(2, "-") returns exactly two results for any valid string_value, it would be better to assign the tuple directly to two variables first and last rather than a seemingly arbitrary-length Vec. I can't seem to do this with a tuple.
There are two instances of collect(), and I wonder if it can be reduced to one (or even zero).
Trivial implementation
fn parse_range(string_value: &str) -> Vec<u8> {
let pos = string_value.find(|c| c == '-').expect("No valid string");
let (first, second) = string_value.split_at(pos);
let first: u8 = first.parse().expect("Not a number");
let second: u8 = second[1..].parse().expect("Not a number");
{ first..second + 1 }.collect()
}
Playground
I would recommend returning a Result<Vec<u8>, Error> instead of panicking with expect/unwrap.
Nightly implementation
My next thought was about the second collect. Here is a code example which uses nightly code, but you won't need any collect at all.
#![feature(conservative_impl_trait, inclusive_range_syntax)]
fn parse_range(string_value: &str) -> impl Iterator<Item = u8> {
let pos = string_value.find(|c| c == '-').expect("No valid string");
let (first, second) = string_value.split_at(pos);
let first: u8 = first.parse().expect("Not a number");
let second: u8 = second[1..].parse().expect("Not a number");
first..=second
}
fn main() {
println!("{:?}", parse_range("3-7").collect::<Vec<u8>>());
}
Instead of calling collect the first time, just advance the iterator:
let mut values = string_value
.splitn(2, "-")
.map(|part| part.parse().unwrap());
let start = values.next().unwrap();
let end = values.next().unwrap();
Do not call .ok().unwrap() — that converts the Result with useful error information to an Option, which has no information. Just call unwrap directly on the Result.
As already mentioned, if you want to return a Vec, you'll want to call collect to create it. If you want to return an iterator, you can. It's not bad even in stable Rust:
fn parse_range(string_value: &str) -> std::ops::Range<u8> {
let mut values = string_value
.splitn(2, "-")
.map(|part| part.parse().unwrap());
let start = values.next().unwrap();
let end = values.next().unwrap();
start..end + 1
}
fn main() {
assert!(parse_range("1-5").eq(1..6));
}
Sadly, inclusive ranges are not yet stable, so you'll need to continue to use +1 or switch to nightly.
Since splitn(2, "-") returns exactly two results for any valid string_value, it would be better to assign the tuple directly to two variables first and last rather than a seemingly arbitrary-length Vec. I can't seem to do this with a tuple.
This is not possible with Rust's type system. You are asking for dependent types, a way for runtime values to interact with the type system. You'd want splitn to return a (&str, &str) for a value of 2 and a (&str, &str, &str) for a value of 3. That gets even more complicated when the argument is a variable, especially when it's set at run time.
The closest workaround would be to have a runtime check that there are no more values:
assert!(values.next().is_none());
Such a check doesn't feel valuable to me.
See also:
What is the correct way to return an Iterator (or any other trait)?
How do I include the end value in a range?

How do I perform operations on different numeric types while computing the average in an idiomatic Rust manner?

I tried to implement a small module where I calculate the mean of a vector:
pub mod vector_calculations {
pub fn mean(vec: &Vec<i32>) -> f32 {
let mut sum: f32 = 0.0;
for el in vec.iter() {
sum = el + sum;
}
sum / vec.len()
}
}
As far as I can tell from the compiler error, there are two problems with my code:
error[E0277]: the trait bound `&i32: std::ops::Add<f32>` is not satisfied
--> src/main.rs:6:22
|
6 | sum = el + sum;
| ^ no implementation for `&i32 + f32`
|
= help: the trait `std::ops::Add<f32>` is not implemented for `&i32`
error[E0277]: the trait bound `f32: std::ops::Div<usize>` is not satisfied
--> src/main.rs:9:13
|
9 | sum / vec.len()
| ^ no implementation for `f32 / usize`
|
= help: the trait `std::ops::Div<usize>` is not implemented for `f32`
I'm trying to add a &i32 with a f32 and I'm trying to divide a f32 with an usize.
I could solve the second error by changing the last line to:
sum / (vec.len() as f32)
Is this is actually how a Rust programmer would do this?
Furthermore, I don't really know how to solve the first error. What has to be done and why?
Yes, dereferencing values and converting numeric types is normal in Rust. These conversions help the programmer recognize that edge cases are possible. As loganfsmyth points out:
An i32 can hold values greater than f32 can represent accurately
Unfortunately, the compiler can't tell what's "correct" for your case, so you still have to be on guard.
For what it's worth, I'd write your current implementation using Iterator::sum:
fn mean(items: &[i32]) -> f64 {
let sum: f64 = items.iter().map(|&v| v as f64).sum();
sum / (items.len() as f64)
}
You should also probably handle the case where the input is empty to avoid dividing by zero:
fn mean(items: &[i32]) -> Option<f64> {
let len = items.len();
if len == 0 {
None
} else {
let sum: f64 = items.iter().map(|&v| v as f64).sum();
Some(sum / (len as f64))
}
}
Using the method from What is a good solution for calculating an average where the sum of all values exceeds a double's limits?, but made a bit more iterator-heavy:
fn mean2(ary: &[i32]) -> f64 {
ary.iter().enumerate().fold(0.0, |avg, (i, &x)| {
avg + ((x as f64 - avg) / (i + 1) as f64)
})
}
See also:
Why is it discouraged to accept a reference to a String (&String) or Vec (&Vec) as a function argument?
.iter() returns an &i32 and Rust does not automatically dereference for type conversions — you are currently trying to change the pointer (&) instead of changing what it's pointing to.
Changing your code to look like this is the simplest way to make it work:
pub mod vector_calculations {
pub fn mean(vec: &Vec<i32>) -> f32 {
let mut sum: f32 = 0.0;
for el in vec.iter() {
sum = *el as f32 + sum; // first dereference the pointer, than cast to f32
}
sum / vec.len() as f32 // cast to f32
}
}
But there are some ways to improve this kind of code:
pub mod vector_calculations {
pub fn mean(vec: &[i32]) -> f32 { // accept a slice instead of a vector
// it now allows arrays, slices, and vectors
// but now you can't add or remove items
// during this function call.
let mut sum: i32 = 0; // as the sum is still a whole number, changing the type
// should make it slightly easier to understand.
for el in vec.iter() {
sum = el + sum; // now this works without changing the type of el
// you don't even need to dereference el anymore
// as Rust does it automatically.
}
sum as f32 / vec.len() as f32 // now you need to cast to f32 twice at the end
}
}

How to allow function to work with integers or floats?

I found a function to compute a mean and have been playing with it. The code snippet below runs, but if the data inside the input changes from a float to an int an error occurs. How do I get this to work with floats and integers?
use std::borrow::Borrow;
fn mean(arr: &mut [f64]) -> f64 {
let mut i = 0.0;
let mut mean = 0.0;
for num in arr {
i += 1.0;
mean += (num.borrow() - mean) / i;
}
mean
}
fn main() {
let val = mean(&mut vec![4.0, 5.0, 3.0, 2.0]);
println!("The mean is {}", val);
}
The code in the question doesn't compile because f64 does not have a borrow() method. Also, the slice it accepts doesn't need to be mutable since we are not changing it. Here is a modified version that compiles and works:
fn mean(arr: &[f64]) -> f64 {
let mut i = 0.0;
let mut mean = 0.0;
for &num in arr {
i += 1.0;
mean += (num - mean) / i;
}
mean
}
We specify &num when looping over arr, so that the type of num is f64 rather than a reference to f64. This snippet would work with both, but omitting it would break the generic version.
For the same function to accept floats and integers alike, its parameter needs to be generic. Ideally we'd like it to accept any type that can be converted into f64, including f32 or user-defined types that defin such a conversion. Something like this:
fn mean<T>(arr: &[T]) -> f64 {
let mut i = 0.0;
let mut mean = 0.0;
for &num in arr {
i += 1.0;
mean += (num as f64 - mean) / i;
}
mean
}
This doesn't compile because x as f64 is not defined for x of an arbitry type. Instead, we need a trait bound on T that defines a way to convert T values to f64. This is exactly the purpose of the Into trait; every type T that implements Into<U> defines an into(self) -> U method. Specifying T: Into<f64> as the trait bound gives us the into() method that returns an f64.
We also need to request T to be Copy, to prevent reading the value from the array to "consume" the value, i.e. attempt moving it out of the array. Since primitive numbers such as integers implement Copy, this is ok for us. Working code then looks like this:
fn mean<T: Into<f64> + Copy>(arr: &[T]) -> f64 {
let mut i = 0.0;
let mut mean = 0.0;
for &num in arr {
i += 1.0;
mean += (num.into() - mean) / i;
}
mean
}
fn main() {
let val1 = mean(&vec![4.0, 5.0, 3.0, 2.0]);
let val2 = mean(&vec![4, 5, 3, 2]);
println!("The means are {} and {}", val1, val2);
}
Note that this will only work for types that define lossless conversion to f64. Thus it will work for u32, i32 (as in the above example) and smaller integer types, but it won't accept for example a vector of i64 or u64, which cannot be losslessly converted to f64.
Also note that this problem lends nicely to functional programming idioms such as enumerate() and fold(). Although outside the scope of this already longish answer, writing out such an implementation is an exercise hard to resist.

How should I call Vec::with_capacity with an i32?

I have a function which allocates a vector on the stack. This code doesn't work:
fn my_func(n: i32) {
let mut v = Vec::with_capacity(n);
}
The compiler says n needs to be a usize. I suppose that makes sense from a type safety point of view, but I need to use n in other calculations where an i32 is called for. What's the proper way to handle this?
Cast to usize.
let n: i32 = 4;
let v = Vec::<i16>::with_capacity(n as usize);

Resources