本文介绍: 1. 对于一次使用类型, 可以直接其实迭代trait.2. 对于容器, 不应该容器本身直接实现迭代器, 而是应该单独创建迭代器类型, 然后对其本身实现 `IntoIterator`

在 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(&amp;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 中对切片的迭代器实现.

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

类型本身:

struct IntRange {
    step: i32,
    end: i32
}

两个迭代器:

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

struct IntRangeIntoIter {
    range: IntRange,
    current: i32,
}

两个迭代器实现:

impl Iterator for IntRangeIter<'_> {
    type Item = i32;
    
    fn next(&amp;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(&amp;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 &amp;'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 &amp;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 = (&amp;v).into_iter();

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

let mut v = vec![1, 2, 3];

// 下面两个调用是等价的
let mutIter = v.iter_mut();
let mutIter = (&amp;mut v).into_iter();

总结

两种类型:

  1. 对于一次性使用的类型, 可以直接对其实现迭代器 trait.

  2. 对于容器, 不应该容器本身直接实现迭代器, 而是应该单独创建迭代器类型, 然后对其本身实现 IntoIterator

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

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

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

原文地址:https://blog.csdn.net/m0_46555380/article/details/134769768

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_35200.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注