Unwrapping a skipped Chars iterator

Viewed 506

Many iterator methods is Rust generate iterators wrapped up in iterators. One such case is the skip method, that skips the given number of elements and yields the remaining ones wrapped in the Skip struct that implements the Iterator trait.

I would like to read a file line by line, and sometimes skip the n first characters of a line. I figured that using Iterator.skip would work, but now I'm stuck figuring out how I can actually unwrap the yielded Chars iterator so I could materialize the remaining &str with chars.as_str().

What is the idiomatic way of unwrapping an iterator in rust? The call chain

let line: &String = ...;
let remaining = line.chars().skip(n).as_str().trim();

raises the error

error[E0599]: no method named `as_str` found for struct `std::iter::Skip<std::str::Chars<'_>>` in the current scope
   --> src/parser/directive_parsers.rs:367:63
    |
367 |         let option_val = line.chars().skip(option_val_indent).as_str().trim();
    |                                                               ^^^^^^ method not found in `std::iter::Skip<std::str::Chars<'_>>`

error: aborting due to previous error
2 Answers

You can retrieve the start byte index of the nth character using the nth() method on the char_indices() iterator on the string. Once you have this byte index, you can use it to get a subslice of the original string:

let line = "This is a line.";
let index = line.char_indices().nth(n).unwrap().0;
let remaining = &line[index..];

Rather than iterate over chars, you can use char_indices to find the exact point at which to take a slice from the string, ensuring that you don't index into the middle of a multi-byte character. This will save on an allocation for each line in the iterator:

input
    .iter()
    .map(|line| {
        let n = 2; // get n from somewhere?
        let (index, _) = line.char_indices().nth(n).unwrap();// better error handling
        &line[index..]
    })
Related