I'm learning rust and ran into the problem. I have this MCVE:
fn main() {
let mut line = String::new();
std::io::stdin()
.read_line(&mut line)
.expect("Failed to read line");
handle_tokens( line.split_ascii_whitespace() );
}
fn handle_tokens( mut it: std::str::SplitAsciiWhitespace ) {
loop {
match it.next() {
None => return,
Some(s) => println!("{}",s),
}
}
}
String::split_ascii_whitespace
returns a SplitAsciiWhitespace
object so I've used that in the signature of handle_tokens
, but std::str::SplitAsciiWhitespace
is an extremely specific type. A generic iterator to a list of strings makes more sense, so that I can choose split_whitespace
or maybe just a generic list of strings.
How can I use documentation or compiler errors to generalize the signature of handle_tokens
?
Here's my failed attempt to answer the question on my own:
I can see that SplitAsciiWhitespace
"Trait Implementations" include:
impl<'a> Iterator for SplitWhitespace<'a>
This is where next()
comes from (I had to inspect source code to verify that). Therefore, I tried using an iterator with fn handle_tokens( mut it: Iterator ) {
but:
error[E0191]: the value of the associated type `Item` (from trait `std::iter::Iterator`) must be specified
--> src/main.rs:10:27
|
10 | fn handle_tokens( mut it: Iterator ) {
| ^^^^^^^^ help: specify the associated type: `Iterator<Item = Type>`
Ok, so Iterator
is too generic to use... I need to tell the compiler what it's wrapping. That makes sense, otherwise I wouldn't be able to dereference it. I had to look in the source code again to see how SplitWhitespace
implements an Iterator and saw type Item = &'a str;
so I tried to specify the Item
with fn handle_tokens( mut it: Iterator<Item = &str>)
, but:
error[E0277]: the size for values of type `(dyn std::iter::Iterator<Item = &str> + 'static)` cannot be known at compilation time
--> src/main.rs:10:19
|
10 | fn handle_tokens( mut it: Iterator<Item = &str> ) {
| ^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::iter::Iterator<Item = &str> + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: all local variables must have a statically known size
= help: unsized locals are gated as an unstable feature
Ok, so I need to specify a size as well. That's strange because while I know the size of str
can't be known at compile-time, the size of &str
should be.
At this point I'm very stuck. I'm also surprised that source-code inspection is necessary when Rust seems to provide such a great built-in documentation support. That makes me think that the method I'm using to answer this question is wrong.