简体   繁体   English

如何从字符串创建迭代器并_将其存储在结构中?

[英]How to create an iterator from string _and_ store it in a struct?

I'm trying to create a constructor for my struct, which would store an iterator over String read from file.我正在尝试为我的结构创建一个构造函数,它将在从文件读取的String上存储一个迭代器。 The problem is that once the functions returns, String is dropped and compiler complains new() returns a value referencing data owned by the current function .问题是一旦函数返回, String被删除并且编译器抱怨new() returns a value referencing data owned by the current function Is there a way to associate String with a struct somehow so that it is not dropped after return?有没有办法以某种方式将String与结构相关联,以便在返回后不会删除它?

I think I understand a complaint here but I don't understand how to deal with it, because I want constructor to deal both with file reading and iterator creation.我想我在这里理解一个抱怨,但我不明白如何处理它,因为我希望构造函数同时处理文件读取和迭代器创建。

pub struct CharStream<'a> {
    input: std::str::Chars<'a>,
    filename: String,
}
impl<'a> CharStream<'a> {
    pub fn new(filename: String) -> CharStream<'a> {
        let mut file = File::open(&filename).unwrap();
        let mut input = String::new();
        file.read_to_string(&mut input);
        CharStream {
            input: input.chars(), // Create an iterator over `input`
            filename: filename,
        }
        // `input` is dropped here
    }
}

I would rename CharStream into FileContents and let it own both the filename and contents of the file as String s.我会将CharStream重命名为FileContents并让它拥有文件的filenamecontents作为String s。 Then when you need to produce a TokenIter to iterate over chunks of char s from the contents you can then create the Chars<'a> on-demand and pass it to TokenIter then.然后,当您需要生成TokenIter以从contents中迭代char块时,您可以按需创建Chars<'a>并将其传递给TokenIter Complete example:完整示例:

use std::fs;
use std::str::Chars;

struct FileContents {
    filename: String,
    contents: String,
}

impl FileContents {
    fn new(filename: String) -> Self {
        let contents = fs::read_to_string(&filename).unwrap();
        FileContents { filename, contents }
    }
    fn token_iter(&self) -> TokenIter<'_> {
        TokenIter {
            chars: self.contents.chars(),
        }
    }
}

struct TokenIter<'a> {
    chars: Chars<'a>,
}

struct Token; // represents some chunk of chars

impl<'a> Iterator for TokenIter<'a> {
    type Item = Token;
    fn next(&mut self) -> Option<Self::Item> {
        self.chars.next(); // call as many times as necessary to create token
        Some(Token) // return created token here
    }
}

fn example(filename: String) {
    let file_contents = FileContents::new(filename);
    let tokens = file_contents.token_iter();
    for token in tokens {
        // more processing here
    }
}

playground 操场

The iterator returned by String::chars() is only valid as long as the original string input lives. String::chars()返回的迭代器仅在原始字符串input存在时才有效。 input is dropped at the end of new , so the iterator cannot be returned from the function. inputnew的末尾被删除,因此无法从 function 返回迭代器。

To solve this, you'd want to store the input string in the struct as well, but then you run into other problems because one struct member can't have a reference to another member of the same struct.为了解决这个问题,您还希望将input字符串存储在结构中,但随后您会遇到其他问题,因为一个结构成员不能引用同一结构的另一个成员。 One reason for this is that the struct would become immovable, since moving it would invalidate the reference.这样做的一个原因是结构将变得不可移动,因为移动它会使引用无效。

The simplest solution is probably to collect the char s into a Vec<char> and store that vector inside the CharStream .最简单的解决方案可能是将char收集到Vec<char>并将该向量存储在CharStream中。 Then add an usize index and write your own Iterator<Item = char> implementation.然后添加一个usize索引并编写您自己的Iterator<Item = char>实现。

Another approach (more memory-efficient) is to store the String itself, and create the Chars iterator on demand, but that would of course result in a different API.另一种方法(更节省内存)是存储String本身,并按需创建Chars迭代器,但这当然会导致不同的 API。

Solutions involving RefCell or similar wrappers are probably also possible.涉及RefCell或类似包装器的解决方案也可能是可能的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM