How to write a fn that processes input and returns an iterator instead of the full result?

StackOverflow https://stackoverflow.com/questions/23380425

  •  12-07-2023
  •  | 
  •  

Pregunta

Forgive me if this is a dumb question, but I'm new to Rust, and having a hard time writing this toy program to test my understanding.

I want a function that given a string, returns the first word in each line, as an iterator (because the input could be huge, I don't want to buffer the result as an array). Here's the program I wrote which collects the result as an array first:

fn get_first_words(input: ~str) -> ~[&str] {
    return input.lines_any().filter_map(|x| x.split_str(" ").nth(0)).collect();
}

fn main() {
    let s = ~"Hello World\nFoo Bar";
    let words = get_words(s);
    for word in words.iter() {
        println!("{}", word);
    }
}

Result (as expected):

Hello
Foo

How do I modify this to return an Iterator instead? I'm apparently not allowed to make Iterator<&str> the return type. If I try @Iterator<&str>, rustc says

error: The managed box syntax is being replaced by the `std::gc::Gc` and `std::rc::Rc` types. Equivalent functionality to managed trait objects will be implemented but is currently missing.

I can't figure out for the life of me how to make that work.

Similarly, trying to return ~Iterator<&str> makes rustc complain that the actual type is std::iter::FilterMap<....blah...>.

In C# this is really easy, as you simply return the result of the equivalent map call as an IEnumerable<string>. Then the callee doesn't have to know what the actual type is that's returned, it only uses methods available in the IEnumerable interface.

Is there nothing like returning an interface in Rust??

(I'm using Rust 0.10)

¿Fue útil?

Solución

I believe that the equivalent of the C# example would be returning ~Iterator<&str>. This can be done, but must be written explicitly: rather than returning x, return ~x as ~Iterator<&'a str>. (By the way, your function is going to have to take &'a str rather than ~str—if you don’t know why, ask and I’ll explain.)

This is not, however, idiomatic Rust because it is needlessly inefficient. The idiomatic Rust is to list the return type explicitly. You can specify it in one place like this if you like:

use std::iter::{FilterMap, Map};
use std::str::CharSplits;

type Foo = FilterMap<'a, &'a str, &'a str,
                     Map<'a, &'a str, &'a str,
                         CharSplits<'a, char>>>

And then list Foo as the return type.

Yes, this is cumbersome. At present, there is no such thing as inferring a return type in any way. This has, however, been discussed and I believe it likely that it will come eventually in some syntax similar to fn foo<'a>(&'a str) -> Iterator<&'a str>. For now, though, there is no fancy sugar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top