Experience, but let's pretend I didn't have that. How could I find it out?
Here's the easy way: make an assignment or similar that you know won't work, and the compiler will generally tell you what the type is.
fn first_word(s: &String) -> usize {
let bytes = s.as_bytes();
for something in bytes.iter().enumerate() {
let () = something; // <-- assignment you know will fail
let (i, &item) = something;
if item == b' ' {
return i;
}
}
s.len();
}
4 | let () = something;
| ^^ --------- this expression has type `(usize, &u8)`
Let me lay some breadcrumbs so you can build your own experience more methodically, though. First of all, from this thread itself: if (i, &item)
works, the iteration type must be a 2-typle with the last element being some sort of reference, so that's a pretty good hint on its own.
Another thing you will learn with experience is that when you have an iterator chain like bytes.iter().enumerate()
, the end of the chain is probably going to be a method on the Iterator
trait. You could look up those methods in the documentation. In this case, that's enumerate
. If you hover on the β, it will tell you:
Notable traits for Enumerate<I>
impl<I> Iterator for Enumerate<I>
where
I: Iterator,
type Item = (usize, <I as Iterator>::Item);
What does this mean? It means the iterator item type is a 2-tuple (like we figured out already), and the last element is the same as the previous iterator in the chain. So now we need to know what bytes.iter()
's iterator item type is.
Over time, you'll get to know many common iterator methods well enough you won't have to look them up.
Next bit of experience: by convention, .iter()
will give an iterator over shared references (&_)
, and .iter_mut()
will give an iterator over exclusive references (&mut _
). If you knew that convention, you could make a good guess that bytes.iter()
has &u8
as the iterator item, and you'd be correct.
If you wanted to look that up in the documentation, you could
You have a &[u8]
, so the iterator item type is &u8
, indeed.
If you didn't know you had a &[u8]
...
You have s: &String
and bytes = s.as_bytes()
. What does that do?
So bytes
is a &[u8]
since that's what as_bytes
returns.
Or instead of chasing documentation, use the assignment trick again.
let bytes: () = s.as_bytes();
2 | let bytes: () = s.as_bytes();
| -- ^^^^^^^^^^^^ expected `()`, found `&[u8]`