简体   繁体   English

如何展平使用引用的迭代器

[英]How to flatten iterator that uses references

I am using the memmap2 crate to read some large binary files, and I am using the midasio library which provides some "viewer" structures that just reference inner structures in the byte slice.我正在使用memmap2 crate 来读取一些大型二进制文件,并且我正在使用midasio库,它提供了一些“查看器”结构,这些结构仅引用字节片中的内部结构。

From a slice of bytes (the memory map) I can create a FileView , with which I can iterate over EventView s, with which I can iterate over BankView s.从一片字节(内存映射)我可以创建一个FileView ,我可以用它来迭代EventView s,我可以用它来迭代BankView s。 All these just reference to the underlying memory mapped slice.所有这些都只是引用底层的内存映射切片。

It usually is trivial to iterate through the BankViews in a set of files as:在一组文件中迭代BankViews通常是微不足道的:

Minimal working example:最小的工作示例:

Cargo.toml货运.toml

[dependencies]
midasio = "0.3"
memmap2 = "0.5"

and main.rs和 main.rs

use std::path::PathBuf;
use std::fs::File;
use memmap2::Mmap;
use midasio::read::file::FileView;

fn main() {
    let args: Vec<PathBuf> = Vec::new(); // Just the name of some files
    for path in args {
        let file = File::open(path).unwrap();
        let mmap = unsafe { Mmap::map(&file).unwrap() };

        let file_view = FileView::try_from(&mmap[..]).unwrap();
        for event_view in &file_view {
            for _bank_view in &event_view {
                // Here I am just iterating through all the BankViews
            }
        }
    }
}

I need to "flatten" all these into a single iterator such that whenever I call next() it has the exact same behavior as the nested loop above.我需要将所有这些“展平”到一个迭代器中,这样每当我调用next()时,它的行为就与上面的嵌套循环完全相同。 How can I do this?我怎样才能做到这一点?

I need to do it because I want to use the Cursive library and loop through BankView s by pressing a "next" button.我需要这样做,因为我想使用 Cursive 库并通过按“下一步”按钮循环通过BankView s。 So I need to control each "next" with a single function that, hopefully, just calls next on the massive iterator.所以我需要用一个函数来控制每个“下一个”,希望它只在大规模迭代器上调用下一个。

I tried我试过了

use std::path::PathBuf;
use std::fs::File;
use memmap2::Mmap;
use midasio::read::file::FileView;

fn main() {
    let args: Vec<PathBuf> = Vec::new();
    let iterator = args
        .iter()
        .map(|path| {
            let file = File::open(path).unwrap();
            let mmap = unsafe { Mmap::map(&file).unwrap() };

            FileView::try_from(&mmap[..]).unwrap()
        })
        .flat_map(|file_view| file_view.into_iter())
        .flat_map(|event_view| event_view.into_iter());
}

And this gives me the errors:这给了我错误:

error[E0515]: cannot return value referencing local variable `mmap`
  --> src/main.rs:14:13
   |
14 |             FileView::try_from(&mmap[..]).unwrap()
   |             ^^^^^^^^^^^^^^^^^^^^----^^^^^^^^^^^^^^
   |             |                   |
   |             |                   `mmap` is borrowed here
   |             returns a value referencing data owned by the current function

error[E0515]: cannot return reference to function parameter `file_view`
  --> src/main.rs:16:31
   |
16 |         .flat_map(|file_view| file_view.into_iter())
   |                               ^^^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function

error[E0515]: cannot return reference to function parameter `event_view`
  --> src/main.rs:17:32
   |
17 |         .flat_map(|event_view| event_view.into_iter());
   |                                ^^^^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function

For more information about this error, try `rustc --explain E0515`.
error: could not compile `ugly_iteration` due to 3 previous errors

This is problematic.这是有问题的。 Because the IntoIterator impls borrow self you need to hold both the iterable and the iterator together, and that creates a self-referential struct.因为IntoIterator impls 借用了self ,所以你需要将 iterable 和 iterator 放在一起,这会创建一个自引用结构。 See Why can't I store a value and a reference to that value in the same struct?请参阅为什么我不能在同一个结构中存储一个值和对该值的引用? . .

It looks to me, even though I haven't digged deep, that this is not necessary and this is actually the result of a wrong design of midasio .在我看来,即使我没有深入挖掘,这也没有必要,这实际上是midasio设计错误的结果。 But you can't do much regarding that, other than patching the library or sending a PR and hoping for it to be accepted soon (if you want to change that, I think it is enough to change the&'a FileView<'a> and &'a EventView<'a> to &'_ FileView<'a> and &'_ EventView<'a> respectively, though I'm unsure).https://github.com/DJDuque/midasio/pull/8但是你对此无能为力,除了修补库或发送 PR 并希望它很快被接受(如果你想改变它,我认为改变&'a FileView<'a>就足够了&'a FileView<'a>&'a EventView<'a>分别到&'_ FileView<'a>&'_ EventView<'a> ,虽然我不确定)。 https://github.com/DJDuque/midasio/pull /8

I don't think there is a good solution.我不认为有一个好的解决方案。 Using iterator adapters is unlikely to work, and creating your own iterator type will require unsafe code or at the very least using a crate like ouroboros .使用迭代器适配器不太可能工作,创建自己的迭代器类型将需要不安全的代码,或者至少使用像ouroboros这样的板条箱。


Edit: With my PR #8 , it still doesn't work verbatim because the Mmap is dropped at the end of the map() but you still need to access it, however this is fixable pretty easily by collecting all Mmap s into a Vec :编辑:使用我的PR #8 ,它仍然无法逐字运行,因为Mmapmap()的末尾被删除,但您仍然需要访问它,但是通过将所有Mmap收集到Vec中很容易解决这个问题:

fn main() {
    let args: Vec<PathBuf> = Vec::new();
    let mmaps = args
        .iter()
        .map(|path| {
            let file = File::open(path).unwrap();
            unsafe { Mmap::map(&file).unwrap() }
            
        })
        .collect::<Vec<_>>();
    let iterator = mmaps
        .iter()
        .map(|mmap| FileView::try_from(&mmap[..]).unwrap())
        .flat_map(|file_view| file_view.into_iter())
        .flat_map(|event_view| event_view.into_iter());
}

Returning this iterator from a function is still not going to work, unfortunately.不幸的是,从函数中返回这个迭代器仍然不起作用。

暂无
暂无

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

相关问题 用于展平的迭代器与 IntoIterator - Iterator vs IntoIterator for flatten 如何展平 Result 的迭代器<Vec<T> ,E&gt; 返回 Result 的迭代器<T,E>生锈? - How do I flatten an iterator of Result<Vec<T>,E> to return an iterator of Result<T,E> in rust? 如何编写一个返回对自身的引用的迭代器? - How do I write an iterator that returns references to itself? 如何迭代结构集合作为特征对象引用的迭代器? - How to iterate over a collection of structs as an iterator of trait object references? 如何在不消耗迭代器的情况下组合两个引用向量? - How to combine two vectors of references without consuming an iterator? 如何将使用Read特质的代码转换为Iterator特质? - How to convert code that uses the Read trait to use the Iterator trait instead? 将对元组的引用迭代器解压缩为两个引用集合 - Unzip iterator of references to tuples into two collections of references 如何创建一个接受i32迭代器作为值或引用并将它们求和的函数? - How do I create a function that accepts an iterator of i32s as either values or references and sums them? 如何实现对二叉搜索树右边缘值的可变引用的迭代器? - How to implement an iterator of mutable references to the values in the right edges of a Binary Search Tree? 在实现返回可变引用的迭代器时,如何解决“无法为 autoref 推断适当的生命周期”? - How can I fix “cannot infer an appropriate lifetime for autoref” when implementing an iterator that returns mutable references?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM