Reputation: 690
I have the following code-snippets:
1. get the n-th element of a Vec recursively
fn helper<T: Clone>(n: usize, current_n: usize, current_xs: &Vec<T>, accumulator: Option<T>) -> Option<T> {
if current_n > n {
accumulator
} else {
let head = current_xs.get(0).cloned();
let tail = current_xs.clone().into_iter().skip(1).collect();
return helper(n, current_n + 1, &tail, head);
}
}
2. get the length of a Vec recursively
fn helper<T: Clone>(current_xs: &Vec<T>, accumulator: usize) -> usize {
if current_xs.is_empty() {
accumulator
} else {
let tail = current_xs.clone().into_iter().skip(1).collect();
return helper(tail, accumulator + 1)
}
}
My Question is about that line:
let tail = current_xs.clone().into_iter().skip(1).collect();
In the first example the tail
variable is of Type Vec<T>
and in the second example the tail
variable is of type &Vec<?>
.
Questions:
Vec<T>
in the second example?Upvotes: 0
Views: 868
Reputation: 23329
In your second example, collect
can return anything that implements FromIterator<Self::Item>
(here Self::Item
is T
). So the compiler tries to guess the type of tail
by looking at how it is used. When you call helper (tail, …)
, the compiler guesses that tail
should have the same type as the first argument to helper
, aka &Vec<U>
for some as yet unknown type U
. However, &Vec<U>
does not implement FromIterator<T>
, so the compiler bails out at this point.
OTOH when you call helper (&tail, …)
, the compiler guesses that &tail
should have type &Vec<U>
for some U
, and therefore tail
should have type Vec<U>
. The compiler can then continue and determine that U==T
, which gives the complete type of tail
as Vec<T>
.
As an aside, here is a more idiomatic implementation of your first helper
that avoids unnecessary copies. Something similar can be done for the second one:
fn helper<T: Clone> (n: usize, current_n: usize, current_xs: &[T], accumulator: Option<&T>) -> Option<T>
{
if current_n > n {
accumulator.cloned()
} else {
let head = current_xs.get (0);
let tail = ¤t_xs[1..];
return if tail.is_empty() {
None
} else {
helper (n, current_n + 1, tail, head)
};
}
}
fn main() {
let v = vec![1, 2, 3, 4, 5];
println!("Element 3: {:?}", helper (3, 0, &v, None));
println!("Element 10: {:?}", helper (10, 0, &v, None));
}
Upvotes: 2
Reputation: 690
The problem is:
Example 1: calls the recursive function with
return helper(n, current_n + 1, &tail, head); // &tail
Example 2: calls the recursive function with:
return helper(tail, accumulator + 1) // tail
Changing tail
to &tail
everything works.
At the moment I can't exactly explain why, so i would wait to accept this as correct answer and hope someone else can completely answer it.
Upvotes: -1