I'm trying to write a function which accepts a list of tokens. But I'm having problems making it general enough to handle two pretty similar calls:
let s = String::from("-abc -d --echo");
parse( s.split_ascii_whitespace() );
parse( std::env::args() );
String::split_ascii_whitespace()
returns std::str:SplitAsciiWhitespace
which implements Iterator<Item=&'a str>
.std::env::args()
returns std::env::Args
which implements Iterator<Item=String>
.Is there a way for me to write a function signature for parse
that will accept both methods?
My solution right now requires duplicating function bodies:
fn main() {
let s = String::from("-abc -d --echo");
parse_args( s.split_ascii_whitespace() );
parse_env( std::env::args() );
}
fn parse_env<I: Iterator<Item=String>>(mut it: I) {
loop {
match it.next() {
None => return,
Some(s) => println!("{}",s),
}
}
}
fn parse_args<'a, I: Iterator<Item=&'a str>>(mut it: I) {
loop {
match it.next() {
None => return,
Some(s) => println!("{}",s),
}
}
}
If not possible, then some advice on how to use the traits so the functions can use the same name would be nice.
You can require the item type to be AsRef<str>
, which will include both &str
and String
:
fn parse<I>(mut it: I)
where
I: Iterator,
I::Item: AsRef<str>,
{
loop {
match it.next() {
None => return,
Some(s) => println!("{}", s.as_ref()),
}
}
}
Depending on your use case, you could try:
fn main() {
let s = String::from("-abc -d --echo");
parse( s.split_ascii_whitespace() );
parse( std::env::args() );
}
fn parse<T: std::borrow::Borrow<str>, I: Iterator<Item=T>>(mut it: I) {
loop {
match it.next() {
None => return,
Some(s) => println!("{}",s.borrow()),
}
}
}
I used Borrow
as a means to get to a &str
, but your concrete use case may be served by other, possibly custom, traits.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With