Rust可迭代类型迭代器正确创建自定义可迭代类型的方法

 更新时间:2023年12月08日 09:40:14   作者:SlimeNull  
在 Rust 中, 如果一个类型实现了 Iterator, 那么它会被同时实现 IntoIterator, 具体逻辑是返回自身, 因为自身就是迭代器,这篇文章主要介绍了Rust可迭代类型迭代器正确创建自定义可迭代类型的方法,需要的朋友可以参考下

在 Rust 中, for 语句的执行依赖于类型对于 IntoIterator 的实现, 如果某类型实现了这个 trait, 那么它就可以直接使用 for 进行循环.

直接实现

在 Rust 中, 如果一个类型实现了 Iterator, 那么它会被同时实现 IntoIterator, 具体逻辑是返回自身, 因为自身就是迭代器.

但是如果自身就是迭代器的话, 就意味着自身必须存储迭代状态, 例如当前迭代的位置. 如果是这样的话, 迭代器就只能被使用一次. 况且自身直接被传入 into_iter 方法后, 所有权被转移, 该对象就无法被再次使用了.

定义类型本身:

struct IntRange {
    current: i32,
    step: i32,
    end: i32
}

直接为其实现迭代器:

impl Iterator for IntRange {
    type Item = i32;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.end {
            return None;
        } else {
            let current = self.current;
            self.current += self.step;
            return Some(current);
        }
    }
}

使用该类型:

let range = IntRange { current: 0, step: 1, end: 10 };
for value in range {
    println!("v: {}", value);
}

所以结论是, 如果你的类型是一次性用品, 你可以直接对其实现 Iterator

手动实现迭代器

如果你向手动实现类似于容器的东西, 那么它当然不是一次性的. 我们应该仿照 Rust 中对切片的迭代器实现.

同时实现会转移所有权和不会转移所有权的两个迭代器对 self&self 都实现 IntoIterator, 这样就可以做不转移所有权的迭代了

类型本身:

struct IntRange {
    step: i32,
    end: i32
}

两个迭代器:

struct IntRangeIter<'a> {
    range: &'a IntRange,
    current: i32,
}
struct IntRangeIntoIter {
    range: IntRange,
    current: i32,
}

两个迭代器实现:

impl Iterator for IntRangeIter<'_> {
    type Item = i32;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.range.end {
            return None;
        } else {
            let current = self.current;
            self.current += self.range.step;
            return Some(current);
        }
    }
}
impl Iterator for IntRangeIntoIter {
    type Item = i32;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.range.end {
            return None;
        } else {
            let current = self.current;
            self.current += self.range.step;
            return Some(current);
        }
    }
}

实现返回两种迭代器的 IntoIterator:

impl<'a> IntoIterator for &'a IntRange {
    type Item = i32;
    type IntoIter = IntRangeIter<'a>;
    fn into_iter(self) -> Self::IntoIter {
        IntRangeIter {
            range: self,
            current: 0
        }
    }
}
impl IntoIterator for IntRange {
    type Item = i32;
    type IntoIter = IntRangeIntoIter;
    fn into_iter(self) -> Self::IntoIter {
        IntRangeIntoIter {
            range: self,
            current: 0
        }
    }
}

使用它:

let range = IntRange { step: 1, end: 10 };
// 可以使用引用来进行 for 循环
for value in &range {
    println!("v: {}", value);
}
// 也可以直接对其进行 for 循环
for value in range {
    println!("v: {}", value);
}

切片对迭代的实现

我们知道, Rust 的切片有一个 iter 方法, 其实它就相当于对当前切片的引用调用 into_iter.

其实, 在调用切片引用的 into_iter 方法时, 本质上就是调用的其 iter 方法. 方法的实现是在 iter 内的.

let v = vec![1, 2, 3];
// 下面两个调用是等价的
let iter1 = v.iter();
let iter2 = (&v).into_iter();

如果你希望实现迭代变量可变的迭代器, 还可以为 &mut T 实现 into_iter, 当然, Rust 内部对于切片的实现, 也是这样的:

let mut v = vec![1, 2, 3];
// 下面两个调用是等价的
let mutIter = v.iter_mut();
let mutIter = (&mut v).into_iter();

总结

两种类型:

  • 对于一次性使用的类型, 可以直接对其实现迭代器 trait.
  • 对于容器, 不应该对容器本身直接实现迭代器, 而是应该单独创建迭代器类型, 然后对其本身实现 IntoIterator

为了方便用户使用, 调用之间的实现应该是这样:

  • 实现 TIntoIterator
  • 实现 &Titer 函数, 返回借用的迭代器.
  • 实训 &mut Titer_mut 函数, 返回可变借用的迭代器.
  • &T&mut T 实现 into_iter 函数, 并在内部调用刚刚实现的 iteriter_mut 函数.

这样, 用户就可以直接调用 iter 方法获得借用的迭代器, 然后使用 map, filter 等方法进行集合的复杂操作了

到此这篇关于Rust可迭代类型迭代器正确创建自定义可迭代类型的方法的文章就介绍到这了,更多相关Rust迭代器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Rust常用功能实例代码汇总

    Rust常用功能实例代码汇总

    通过一系列实用示例展示了Rust在文件操作、网络请求、并发编程、命令行工具以及数据库操作等方面的应用,这些示例不仅展示了 Rust 的强大功能,还提供了实际开发中的指导和参考,通过这些示例,您可以更好地理解 Rust 的特性,并将其应用于您的项目中
    2024-12-12
  • Rust的基础数据类型、变量系统、类型转换以及实战应用

    Rust的基础数据类型、变量系统、类型转换以及实战应用

    本文介绍了Rust的基础数据类型、变量系统、类型转换以及实战应用,涵盖了标量类型、复合类型和字符串类型,通过变量声明、可变性控制、作用域规则以及Shadowing机制的学习,掌握Rust的变量系统,通过实际案例,展示了Rust在实际编程中的应用
    2026-01-01
  • rust流程控制的具体使用

    rust流程控制的具体使用

    在Rust中,控制流包括条件语句、循环和匹配模式等,用于实现程序的逻辑和流程控制,本文就来详细的介绍一下,感兴趣的可以了解一下
    2023-12-12
  • 详解thiserror库在Rust中的使用

    详解thiserror库在Rust中的使用

    在编程中,错误处理是一个至关重要的部分,在Rust中,我们经常使用Result和Option类型来进行错误处理,但有时,我们需要创建自定义的错误类型,这就是thiserror库发挥作用的地方,可以极大的简化代码,所以本文就给大家介绍一下如何使用thiserror
    2023-08-08
  • Rust模块关键词和哈希表详解

    Rust模块关键词和哈希表详解

    文章介绍了Rust编程语言中模块系统、路径控制、as关键字、外部包的使用以及哈希表的操作,主要涵盖了如何通过pub关键字控制模块和结构体的可见性,文章还详细讲解了哈希表的创建、访问、所有权转移、更新操作,感兴趣的朋友一起看看吧
    2026-03-03
  • Rust内存示例深入讲解

    Rust内存示例深入讲解

    内存管理一直是编程中的一大挑战,尤其是在C和C++中,程序员需要手动处理内存分配和释放,这篇文章主要介绍了Rust内存的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-02-02
  • 一文带你了解Rust是如何处理错误的

    一文带你了解Rust是如何处理错误的

    程序在运行的过程中,总是会不可避免地产生错误,而如何优雅地解决错误,也是语言的设计哲学之一。本文就来和大家来了Rust是如何处理错误的,感兴趣的可以了解一下
    2022-11-11
  • Rust 入门之函数和注释实例详解

    Rust 入门之函数和注释实例详解

    这篇文章主要为大家介绍了Rust 入门之函数和注释实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Rust常用特型之Drop特型

    Rust常用特型之Drop特型

    本文主要介绍了Rust常用特型之Drop特型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-03-03
  • Rust 堆内存指针 Box的实现示例

    Rust 堆内存指针 Box的实现示例

    在 Rust 中,Box<T>是最基础、最简洁的智能指针,核心作用是将数据从栈内存转移到堆内存,并通过独占所有权机制管理堆内存的分配与释放,下面就来详细的介绍一下,感兴趣的可以了解一下
    2026-04-04

最新评论