如何在Rust中实现多值迭代器模式?
我有一个迭代器类型的对象,每次调用它时可以返回零个、一个或多个项。我想实现一个标准的如何在Rust中实现多值迭代器模式?,rust,Rust,我有一个迭代器类型的对象,每次调用它时可以返回零个、一个或多个项。我想实现一个标准的IterAPI,即next返回选项,这样就可以逐项消费 在Clojure中,我可能会使用mapcat(“映射并连接”)来实现这一点 我当前的解决方案(感谢@Ryan)使用了平面地图,但仍然需要大量的分配: // Desired input: // A stateful object that implements an iterator which returns a number of results each
Iter
API,即next
返回选项
,这样就可以逐项消费
在Clojure中,我可能会使用mapcat
(“映射并连接”)来实现这一点
我当前的解决方案(感谢@Ryan)使用了平面地图
,但仍然需要大量的分配:
// Desired input:
// A stateful object that implements an iterator which returns a number of results each time.
// The real code is a bit more complicated, this is the minimal example.
struct MyThing {
counter: i32,
}
impl Iterator for MyThing {
type Item = Vec<String>;
fn next(&mut self) -> Option<Vec<String>> {
self.counter += 1;
if self.counter == 4 {
self.counter = 1;
}
match self.counter {
1 => Some(vec!["One".to_string()]),
2 => Some(vec!["One".to_string(), "Two".to_string()]),
3 => Some(vec![
"One".to_string(),
"Two".to_string(),
"Three".to_string(),
]),
_ => Some(vec![]),
}
}
}
fn main() {
let things = MyThing { counter: 0 };
// Missing piece, though the following line does the job:
let flattened = things.flat_map(|x| x);
// However this requires a heap allocation at each loop.
// Desired output: I can iterate, item by item.
for item in flattened {
println!("{:?}", item);
}
}
//所需输入:
//一个有状态的对象,它实现了一个迭代器,每次都返回许多结果。
//真正的代码有点复杂,这是最简单的例子。
结构神话{
柜台:i32,
}
impl神话迭代器{
项目类型=Vec;
fn下一步(&mut self)->选项{
自计数器+=1;
如果self.counter==4{
self.counter=1;
}
匹配自动计数器{
1=>Some(vec![“One.”to_string()),
2=>Some(vec![“一.到字符串(),“两.到字符串()]),
3=>一些(vec[
“一”。到字符串(),
“两个”。to_string(),
“三个”。to_string(),
]),
_=>一些(vec![]),
}
}
}
fn main(){
让事物=虚构{计数器:0};
//缺少一块,尽管以下行可以完成此工作:
让展平=事物。展平映射(| x | x);
//但是,这需要在每个循环中分配堆。
//所需输出:我可以逐项迭代。
对于展平的项目{
println!(“{:?}”,项目);
}
}
鉴于我所看到的创新之处,我想知道是否有一种更惯用、成本更低的方法来实现此模式。如果您知道如何以编程方式生成“内部”值,请将
Vec
替换为您定义的实现迭代器的结构。(从技术上讲,只需要迭代器
,但迭代器
就足够了。)
如您所知,会展平嵌套结构,因此如下所示:
在实际代码中,内部
和外部
在大多数情况下可能与此示例非常不同。例如,如果不执行与分配Vec
等效的操作,就不一定能够编写内部
。因此,这些迭代器的精确形状和语义取决于关于用例的具体信息
以上假设internal
在某种程度上是有用的,或者更容易单独实现。您可以很容易地编写一个在序列上迭代的结构,而无需展平,但是您还必须将内部迭代器状态(索引字段)放入外部中:
struct Outer {
index: usize,
counter: i32,
}
impl Iterator for Outer {
type Item = String;
fn next(&mut self) -> Option<String> {
static WORDS: [&str; 3] = ["One", "Two", "Three"];
let result = WORDS.get(self.index).map(|r| r.to_string());
self.index += 1;
if self.index >= self.counter as usize {
self.counter = 1 + self.counter % 3;
self.index = 0;
};
result
}
}
fn main() {
let things = Outer { counter: 1, index: 0 };
for item in things.take(100) {
println!("{:?}", item);
}
}
struct-Outer{
索引:usize,
柜台:i32,
}
外部函数的impl迭代器{
类型项=字符串;
fn下一步(&mut self)->选项{
静态词:[&str;3]=[“一”、“二”、“三”];
让result=WORDS.get(self.index).map(|r | r.to_string());
自指数+=1;
如果self.index>=使用self.counter{
self.counter=1+self.counter%3;
self.index=0;
};
结果
}
}
fn main(){
让things=Outer{counter:1,index:0};
对于物品中的物品。取(100){
println!(“{:?}”,项目);
}
}
你能进一步解释一下你的问题吗:(a)你的“迭代器类型对象”到底返回了什么,(b)为什么iterator::flat_map
是不够的,(c)你所说的“小缓冲迭代器”是什么意思?你的问题说你想“实现一个多值迭代器”,但这对我来说没有任何意义。您声明您已经有了一个“迭代器类型对象”,那么为什么要询问如何实现它呢?示例分配是因为迭代器本身进行分配。如果您有一个不分配的迭代器,对其调用.flat\u map()
不会导致它分配。在您的实际实现中,这些项来自哪里?您可以通过维护第二个计数器来跟踪哪个数字来避免Vec
s,但如果很难说什么适用于您的真实代码,则没有一个代表性的示例。
struct Outer {
counter: i32,
}
impl Iterator for Outer {
type Item = Inner;
fn next(&mut self) -> Option<Inner> {
self.counter = 1 + self.counter % 3;
Some(Inner::new(self.counter as usize))
}
}
let things = Outer { counter: 0 };
for item in things.flat_map(|x| x).take(100) {
println!("{:?}", item);
}
struct Outer {
index: usize,
counter: i32,
}
impl Iterator for Outer {
type Item = String;
fn next(&mut self) -> Option<String> {
static WORDS: [&str; 3] = ["One", "Two", "Three"];
let result = WORDS.get(self.index).map(|r| r.to_string());
self.index += 1;
if self.index >= self.counter as usize {
self.counter = 1 + self.counter % 3;
self.index = 0;
};
result
}
}
fn main() {
let things = Outer { counter: 1, index: 0 };
for item in things.take(100) {
println!("{:?}", item);
}
}