Разворачивание итератора пропущенных символов

#string #rust #iterator #substring

#строка #Ржавчина #итератор #подстрока

Вопрос:

Многие методы итератора Rust генерируют итераторы, завернутые в итераторы. Одним из таких случаев является skip метод, который пропускает заданное количество элементов и выдает оставшиеся, завернутые в Skip структуру, которая реализует Iterator признак.

Я хотел бы читать файл построчно и иногда пропускать n первые символы строки. Я полагал, что использование Iterator.skip сработает, но теперь я застрял, выясняя, как я могу фактически развернуть полученный Chars итератор, чтобы я мог материализовать оставшийся amp;str с chars.as_str() помощью.

Каков идиоматический способ разворачивания итератора в rust? Цепочка вызовов

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

вызывает ошибку

 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
  

Комментарии:

1. Skip это просто итератор по элементам базового итератора, но без первых n элементов. Просто используйте его как итератор. Вложенный итератор в вашей ситуации звучит несвязанно — это потому, что вы выполняете итерацию по строкам, а затем по символам.

2. Skip является итератором. Вам нужно .collect() это.

3. На самом деле звучит так, как будто вы вообще не хотите выполнять итерацию по символам. Вы, вероятно, просто хотите взять фрагмент строк? Выполняя это с помощью символов, вам нужно будет собрать в a String , что кажется ненужным выделением.

4. @PeterHall Да, брать фрагменты было бы замечательно, но я заранее не знаю индексов байтов моих символов. Вот почему я был расточителен и имел дело в основном с Chars итераторами.

5. Это означает, что вы должны обрабатывать все допустимые UTF-8? В зависимости от вашего варианта использования, переход вручную .char_indices() может быть значительным улучшением. Тем более, что это экономит вам дополнительное выделение. Однако попахивает преждевременной оптимизацией, сделайте пометку в коде и двигайтесь дальше.

Ответ №1:

Вы можете получить начальный байтовый индекс n-го символа, используя nth() метод в char_indices() итераторе строки. Как только у вас будет этот байтовый индекс, вы можете использовать его для получения фрагмента исходной строки:

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

Ответ №2:

Вместо повторения chars вы можете использовать char_indices для нахождения точной точки, в которой нужно взять фрагмент из строки, гарантируя, что вы не будете индексировать середину многобайтового символа. Это позволит сэкономить на выделении для каждой строки в итераторе:

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