Rust双端迭代器增强库double-ended-peekable的使用,支持双向peek操作的迭代器扩展功能

Rust双端迭代器增强库double-ended-peekable的使用,支持双向peek操作的迭代器扩展功能

double-ended-peekable是一个Rust库,它为双端迭代器(实现了DoubleEndedIterator trait的类型)提供了双向peek功能。

安装

在项目目录中运行以下Cargo命令:

cargo add double-ended-peekable

或者在Cargo.toml中添加:

double-ended-peekable = "0.1.0"

使用示例

以下是一个使用double-ended-peekable的完整示例:

use double_ended_peekable::DoubleEndedPeekableExt;

fn main() {
    // 创建一个可迭代的集合
    let nums = vec![1, 2, 3, 4, 5];
    
    // 转换为双端peekable迭代器
    let mut iter = nums.into_iter().double_ended_peekable();
    
    // 从前面peek
    println!("Peek from front: {:?}", iter.peek()); // Some(&1)
    
    // 从后面peek
    println!("Peek from back: {:?}", iter.peek_back()); // Some(&5)
    
    // 遍历并打印所有元素
    while let Some(num) = iter.next() {
        println!("Next: {}", num);
        
        // 在遍历过程中可以随时查看下一个或前一个元素
        println!("Next peek: {:?}", iter.peek());
        println!("Previous peek: {:?}", iter.peek_back());
    }
}

功能特点

  1. 支持从迭代器前端和后端peek元素
  2. 不会消耗迭代器中的元素
  3. 与标准库中的Peekable迭代器类似,但增加了反向peek功能

适用场景

  • 需要同时查看迭代器前后元素的算法
  • 解析器或词法分析器实现
  • 需要双向查看数据的处理流程

完整示例演示

下面是一个更完整的示例,展示了如何在实际场景中使用double-ended-peekable库:

use double_ended_peekable::DoubleEndedPeekableExt;

fn main() {
    // 创建一个字符串切片集合
    let words = vec!["Rust", "is", "awesome", "and", "fast"];
    
    // 创建双端peekable迭代器
    let mut word_iter = words.into_iter().double_ended_peekable();
    
    // 检查前后元素
    println!("First word: {:?}", word_iter.peek()); // Some("Rust")
    println!("Last word: {:?}", word_iter.peek_back()); // Some("fast")
    
    // 处理中间元素
    while let Some(word) = word_iter.next() {
        println!("Current word: {}", word);
        
        // 检查是否到达中间点
        if let (Some(next_word), Some(prev_word)) = (word_iter.peek(), word_iter.peek_back()) {
            println!("Next word will be: {}, previous word was: {}", next_word, prev_word);
            
            // 示例:当遇到特定词时查看前后元素
            if word == "awesome" {
                println!("Found 'awesome'! Before it was 'is', after it will be 'and'");
            }
        }
    }
    
    // 另一个示例:处理数字序列
    let numbers = (1..=10).collect::<Vec<_>>();
    let mut num_iter = numbers.into_iter().double_ended_peekable();
    
    // 使用peek_back检查是否包含偶数
    if let Some(last) = num_iter.peek_back() {
        if last % 2 == 0 {
            println!("Last number {} is even", last);
        }
    }
    
    // 遍历时跳过某些元素
    while let Some(n) = num_iter.next() {
        if n % 3 == 0 {
            println!("Skipping number divisible by 3: {}", n);
            continue;
        }
        
        println!("Processing number: {}", n);
        
        // 查看下一个元素决定是否继续
        if let Some(next_n) = num_iter.peek() {
            if *next_n > 7 {
                println!("Next number is greater than 7, stopping early");
                break;
            }
        }
    }
}

注意事项

  1. 该库需要迭代器实现DoubleEndedIterator trait
  2. peek操作返回的是引用,不会消耗迭代器元素
  3. 在迭代过程中可以随时使用peek和peek_back查看元素
  4. 适用于需要前瞻或后顾处理的场景

1 回复

Rust双端迭代器增强库double-ended-peekable使用指南

概述

double-ended-peekable是一个Rust库,它为双端迭代器提供了增强的peek功能,允许你同时向前和向后查看迭代器中的元素而不会消耗它们。

功能特点

  • 支持双向peek操作
  • 保持原始迭代器的所有功能
  • 零成本抽象(在Rust中意味着没有运行时开销)
  • 与标准库的Peekable类似但功能更强大

安装

在Cargo.toml中添加依赖:

[dependencies]
double-ended-peekable = "0.1"

基本使用方法

创建双端peekable迭代器

use double_ended_peekable::DoubleEndedPeekableExt;

fn main() {
    let vec = vec![1, 2, 3, 4, 5];
    let mut iter = vec.into_iter().double_ended_peekable();
    
    // 现在可以使用双向peek功能
}

双向peek操作

let mut iter = vec![1, 2, 3, 4, 5].into_iter().double_ended_peekable();

// 向前peek
assert_eq!(iter.peek(), Some(&1));
assert_eq!(iter.peek_next(), Some(&2));

// 向后peek
assert_eq!(iter.peek_prev(), None);  // 还没有消耗任何元素

// 前进一个元素
iter.next();

// 现在可以向后peek了
assert_eq!(iter.peek_prev(), Some(&1));
assert_eq!(iter.peek(), Some(&2));
assert_eq!(iter.peek_next(), Some(&3));

完整示例

use double_ended_peekable::DoubleEndedPeekableExt;

fn process_sequence<I: DoubleEndedIterator>(iter: I) {
    let mut iter = iter.double_ended_peekable();
    
    while let Some(current) = iter.next() {
        let prev = iter.peek_prev().copied();
        let next = iter.peek().copied();
        
        println!(
            "Processing {}: previous was {:?}, next is {:?}",
            current, prev, next
        );
        
        // 根据前后元素决定处理逻辑
        match (prev, next) {
            (Some(p), Some(n)) if p < current && n > current => {
                println!("  -> Peak detected!");
            },
            (Some(p), Some(n)) if p > current && n < current => {
                println!("  -> Valley detected!");
            },
            _ => {}
        }
    }
}

fn main() {
    let data = vec![1, 3, 5, 4, 2, 6, 8];
    process_sequence(data.into_iter());
}

高级用法

与双端迭代器结合使用

use double_ended_peekable::DoubleEndedPeekableExt;

fn main() {
    let mut iter = (1..=10).double_ended_peekable();
    
    // 从前面消耗几个元素
    assert_eq!(iter.next(), Some(1));
    assert_eq!(iter.next(), Some(2));
    
    // 从后面消耗几个元素
    assert_eq!(iter.next_back(), Some(10));
    assert_eq!(iter.next_back(), Some(9));
    
    // 现在peek各个方向
    assert_eq!(iter.peek(), Some(&3));      // 下一个前面的元素
    assert_eq!(iter.peek_next(), Some(&4));  // 下下个前面的元素
    assert_eq!(iter.peek_prev(), Some(&2));  // 前一个前面的元素
    assert_eq!(iter.peek_back(), Some(&8));  // 下一个后面的元素
}

实现自定义逻辑

use double_ended_peekable::DoubleEndedPeekableExt;

fn find_symmetric_pairs<I: DoubleEndedIterator<Item = i32>>(iter: I) -> Vec<(i32, i32)> {
    let mut iter = iter.double_ended_peekable();
    let mut result = Vec::new();
    
    while let (Some(front), Some(back)) = (iter.peek(), iter.peek_back()) {
        if front == back {
            result.push((*front, *back));
            iter.next();
            iter.next_back();
        } else if front < back {
            iter.next();
        } else {
            iter.next_back();
        }
    }
    
    result
}

fn main() {
    let nums = vec![1, 2, 3, 4, 5, 4, 3, 2, 1];
    let pairs = find_symmetric_pairs(nums.into_iter());
    println!("Symmetric pairs: {:?}", pairs);
    // 输出: Symmetric pairs: [(1, 1), (2, 2), (3, 3), (4, 4)]
}

完整示例demo

下面是一个结合了多种功能的完整示例,展示如何在实际场景中使用double-ended-peekable:

use double_ended_peekable::DoubleEndedPeekableExt;

// 处理数字序列,检测极值和趋势
fn analyze_sequence<I: DoubleEndedIterator<Item = i32>>(iter: I) {
    let mut iter = iter.double_ended_peekable();
    let mut count = 0;
    
    println!("开始分析序列...");
    
    while let Some(current) = iter.next() {
        count += 1;
        let prev = iter.peek_prev().copied();
        let next = iter.peek().copied();
        
        // 打印当前位置信息
        println!("\n元素 #{}: {}", count, current);
        println!("前驱元素: {:?}, 后继元素: {:?}", prev, next);
        
        // 检测极值点
        match (prev, next) {
            (Some(p), Some(n)) if p < current && n < current => {
                println!("↗↘ 检测到局部最大值: {}", current);
            },
            (Some(p), Some(n)) if p > current && n > current => {
                println!("↘↗ 检测到局部最小值: {}", current);
            },
            _ => {}
        }
        
        // 检测趋势
        match (prev, next) {
            (Some(p), Some(n)) if p < current && current < n => {
                println!("↑ 上升趋势");
            },
            (Some(p), Some(n)) if p > current && current > n => {
                println!("↓ 下降趋势");
            },
            _ => {}
        }
        
        // 如果到达序列末尾
        if iter.peek().is_none() {
            println!("已到达序列末尾");
        }
    }
    
    println!("分析完成,共处理{}个元素", count);
}

fn main() {
    // 创建一个测试序列
    let test_data = vec![1, 2, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2];
    
    println!("测试序列: {:?}", test_data);
    analyze_sequence(test_data.into_iter());
}

注意事项

  1. 该库需要迭代器实现DoubleEndedIterator trait
  2. peek_prev()只有在已经消耗至少一个元素后才会返回Some
  3. 所有peek操作都不会消耗迭代器中的元素
  4. 性能与标准库的Peekable相当

这个库特别适合需要同时查看前后元素的算法场景,如解析器、模式匹配等需要"前瞻"和"后顾"的情况。

回到顶部