Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust String vs &str iterators

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.

like image 521
Stewart Avatar asked Jan 25 '23 20:01

Stewart


2 Answers

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()),
        }
    }
}
like image 137
Sven Marnach Avatar answered Jan 29 '23 08:01

Sven Marnach


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.

like image 33
phimuemue Avatar answered Jan 29 '23 10:01

phimuemue