I am trying to create my own implementation of some example. I met an error but I am not sure to understand the solution.
here the code and the error :
use std::str::FromStr;
fn main() {
let numbers: Vec<u64> = std::env::args()
.skip(1)
.map(|arg| u64::from_str(&arg).expect("Error parsing argument"))
.collect()
;
if numbers.len() == 0 {
eprintln!("Usage: <app> NUMBER ...");
std::process::exit(1);
}
println!("{:#?}", numbers);
let mut first = numbers[0];
for current in numbers[1..] {
first = gcd(first, current);
}
println!("the gcd is {:#?}", first);
}
fn gcd(mut a: u64, mut b: u64) -> u64 {
assert!(a != 0 && b != 0);
while a != 0 {
if a < b {
let temp = a;
a = b;
b = temp;
}
a = a % b;
}
b
}
The error :
error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
--> src/main.rs:19:20
|
19 | for current in numbers[1..] {
| ^^^^^^^^^^^^ the trait `IntoIterator` is not implemented for `[u64]`
|
= note: the trait bound `[u64]: IntoIterator` is not satisfied
= note: required for `[u64]` to implement `IntoIterator`
help: consider borrowing here
|
19 | for current in &numbers[1..] {
| +
19 | for current in &mut numbers[1..] {
| ++++
One solution is to uses borrowing this way :
let mut first = numbers[0];
for current in &numbers[1..] {
first = gcd(first, *current);
}
but i am not sure to understand how borrowing allow to convert [u64] to iterator ?
and if I understand *current here can be used like mut ?
First of all, for loops require the value being iterated over (i.e. the value after the in keyword) to implement IntoIterator. So if a type doesn't implement IntoIterator, you can't iterate over it.
[T] does not implement IntoIterator. So you can't iterate over it. Simple as that.
Now, &[T] and &mut [T]do implement IntoIterator, so you can iterate over those.
But okay, why is that the case? IntoIterator looks like this:
pub trait IntoIterator {
type Item;
type IntoIter: Iterator<Item = Self::Item>;
fn into_iter(self) -> Self::IntoIter;
}
Ignore the type stuff and just concentrate on into_iter. Note that it takes the receiver selfby value. This is why [T] cannot implement IntoIterator. [T] is a "dynamically sized type": the compiler does not (and cannot) know how big values of that type are. As a result, you cannot have variables of these types, you can only refer to them through a pointer.
This is, incidentally, what that "the size for values of type [u64] cannot be known at compilation time" error is talking about.
On the other hand, implementing IntoIterator for &[T] means that self is of type &[T] which is fine.
That's why you have to borrow a [u64] in order to iterate over it.
Edit: oops, forgot to address this. No. Because you use &numbers[1..], current has type &u64. If you want to mutate, you need to use &mut numbers[1..], which will make current be a &mut u64.
You are confusing a reference-typed place that is itself mutable with a reference that points to a mutable place. Those are not the same thing. The former allows ypu to change the reference itself (to point to a different place), while the latter allows you to change the pointed place through the reference.