Let's tackle these one-by-one.
print_max_1
Here, largest
is a mutable variable that holds an immutable reference to a u16
(i.e. it holds a &u16
). Within the loop, number
is also a &u16
which, like largest
, is borrowed from number_list
. Both number
and larger
are implicitly dereferenced to perform the comparison. If the value referenced by number
is greater than that referenced by larger
, you store a copy of the immutable reference contained in number
into largest
.
print_max_2
In this case, since number_list
is itself borrowed, the analysis of print_max_2
is identical to print_max_1
.
print_max_3
Here, largest
is a u16
. You are correct that number_list[0]
is copied, but it is worth noting that this copy is cheap. Within the loop, each element of number_list
is copied and stored directly in number
. If number
is greater than largest
, you stored the new greatest value directly in largest
. This is the most optimal of the three implementations you've written, since you do away with all of the unnecessary indirection that references (i.e., pointers) introduce.
print_max_4
Once again, you store a reference to the first element of number_list
in largest
, i.e. largest
is a &u16
. Similarly, as was the case in print_max_3
, number
is a u16
, which will hold copies of the elements from number_list
. However, as you noted, this function is the problem child.
Within the loop, the compiler will point out two errors:
- You attempt to compare two distinct types which don't have a
PartialOrder
defined, namely largest
which is a &u16
and number
which is a u16
. Rust isn't in the business of trying to guess what you mean by this comparison, so in order fix this, you'll have to make both number
and largest
the same type. In this case, what you want to do is explicitly dereference largest
using the *
operator, which will allow you to compare the u16
it points to with the u16
contained in number
. This final comparison looks like
if number > *largest { ... }
- You attempt to store a
u16
in a variable of type &u16
, which does not make sense. Unfortunately, here you're going to run into a wall. Within the loop, all you have is the value of the number you copied from number_list
, but largest
needs to hold a reference to a u16
. We can't simply borrow number
here (e.g. by writing largest = &number
), since number
will be dropped (i.e. go out of scope) at the end of the loop. The only way to resolve is is to revert by to print_max_2
by storing the maximum value itself instead of the pointer to it.
As for whether for number in number_list
is a shortcut for for number in number_list.iter()
, the answer is a firm no. The former will take ownership of number_list
, and during each iteration, number
takes ownership of the next value in number_list
. In contrasts, the latter only performs a borrow, and during each iteration of the loop, number
receives an immutable reference to the next element of number_list
.
In this specific case, these two operation appear identical, since taking ownership of an immutable reference simply entails making a copy, which leaves the original owner intact. For more information, see this answer to a related question on the difference between .into_iter()
and .iter()
.