Rust:从 std::Rc 智能指针向量实现迭代器

2024-02-20

我从 Rust 开始,我已经面临数据所有权的问题。

我想实现一个名为的通用结构Port<T>有一个值向量Vec<T>。此外,该结构有一个指向相同类型的其他结构的引用计数指针向量,Vec<Rc<Port<T>>>:

use std::slice::Iter;
use std::rc::Rc;

pub struct Port<T> {
    values: Vec<T>,
    ports: Vec<Rc<Port<T>>>,
}

这个想法如下:有多种类型结构Port<T>。您可以添加类型的值T到给定的端口。每个端口将这些值存储在其values属性。然而,可以使用引用计数指针将一个端口“链接”到其他端口:

impl <T> Port<T> {
    pub fn new() -> Self {
        Self { values: vec![], ports: vec![] }
    }

    pub fn add_value(&mut self, value: T) {
        self.values.push(value);
    }

    pub fn chain_port(&mut self, port: Rc<Port<T>>) {
        if !port.is_empty() {
            self.ports.push(port)
        }
    }

    pub fn is_empty(&self) -> bool {
        self.values.is_empty() || self.ports.is_empty()
    }

    pub fn clear(&mut self) {
        self.values.clear();
        self.ports.clear();
    }
}

到目前为止,代码已编译通过。现在,我想为端口实现一个迭代器,它返回对此端口拥有的值的引用,同时也返回对每个链接端口的迭代器生成的值的引用:

pub struct PortIterator<'a, T> {
    values: Iter<'a, T>,                     // Iterates over values owned by Port<T>
    port: Option<Box<PortIterator<'a, T>>>,  // Pointer to current port iterator
    ports: Vec<Rc<Port<T>>>,                 // Pointers to remaining chained ports
}

// Note that the iterator is created from an immutable reference to Port<T>
impl<'a, T: 'a> IntoIterator for &'a Port<T> {
    type Item = &'a T;  // the iterator returns references to values
    type IntoIter = PortIterator<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        // We clone all the reference-counting pointers so the iterator owns them
        let mut ports = vec![];
        for port in self.ports.iter() {
            ports.push(port.clone())
        }
        PortIterator {values: self.values.iter(), port: None, ports}
    }
}

现在,让我们定义Iterator特质为PortIterator:

impl <'a, T: 'a> Iterator for PortIterator<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        // We first iterate over values of the original port
        if let Some(v) = self.values.next() {
            return Some(v)
        }
        // If the first iterable is done, we try to iterate over a chained port
        if let Some(port) = &mut self.port {
            if let Some(v) = port.next() {
                return Some(v)
            }
        }
        // if the chained port is over, we try to consume the next chained port
        if let Some(port) = self.ports.get(self.next_port) {
            self.next_port += 1;
            self.port = Some(Box::new(port.as_ref().into_iter()));
            return self.next()
        }
        None
    }
}

现在,该程序无法编译。问题好像出在第三个if let块,并且它与生命周期有关。编译器是这样说的:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/modeling/port.rs:69:40
   |
69 |         if let Some(port) = self.ports.get(self.next_port) {
   |                                        ^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 57:5...
  --> src/modeling/port.rs:57:5
   |
57 |     fn next(&mut self) -> Option<Self::Item> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/modeling/port.rs:69:29
   |
69 |         if let Some(port) = self.ports.get(self.next_port) {
   |                             ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 54:7...
  --> src/modeling/port.rs:54:7
   |
54 | impl <'a, T: 'a> Iterator for PortIterator<'a, T> {
   |       ^^
note: ...so that the expression is assignable
  --> src/modeling/port.rs:71:25
   |
71 |             self.port = Some(Box::new(port.as_ref().into_iter()));
   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: expected `Option<Box<PortIterator<'a, _>>>`
              found `Option<Box<PortIterator<'_, _>>>`

我不知道如何处理这个问题。我一直在尝试其他选项和实现,但我一直在原地踏步。


我认为有更简单的方法可以实现您想要实现的目标。让我们从小处开始:你的Port<T>需要一个iter(&self)返回一个迭代器的方法,该迭代器分发&T items:

pub fn iter(&self) -> impl Iterator<Item = &T> {
    // ...
}

该函数需要将迭代器链接起来self.values, i.e. self.values.iter()使用链接端口上的迭代器。你想要写的是这样的:

pub fn iter(&self) -> impl Iterator<Item = &T> {
    self.values
        .iter()
        .chain(self.ports.iter().flat_map(|p| p.iter()))
}

但是,这不会编译,因为编译器抱怨“递归不透明类型”。那是因为类型p.iter()我们是一样的吗impl Iterator<...>,然后它必须包含自身。从概念上讲,这与您在构建时遇到的问题相同PortIterator,你通过装箱解决了这个问题PortIterator。我们可以用同样的方式解决它,通过装箱内部迭代器并动态分派它:

pub fn iter(&self) -> impl Iterator<Item = &T> {
    self.values.iter().chain(
        self.ports
            .iter()
            .flat_map(|p| Box::new(p.iter()) as Box<dyn Iterator<Item = &T>>),
    )
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rust:从 std::Rc 智能指针向量实现迭代器 的相关文章

随机推荐

  • 循环类似命名的 UI 元素 - 也许通过从其名称获取变量?

    我使用 Interface Builder 向视图添加了许多标签 我还有一个要显示的值数组 有没有比使用此代码更好的方法来设置标签 lblTotal1 text NSString stringWithFormat i Seconds int
  • MongoDB - 去除字段中的非数字字符

    我有一个电话号码字段 其中使用了各种随机分隔符 例如 932 555 1515 951 555 1255 952 555 1414 我想遍历已经存在的每个字段并删除非数字字符 那可能吗 无论它是存储为整数还是数字字符串 我都不在乎 它将仅用
  • 从用户输入中读取数学表达式

    我需要能够读取用户输入并将其分解以供以后使用 用户可以输入整数或小数和运算 但我不知道如何读取它 用户输入的示例是4 8 3 12 or 3 2 3 or 12 16 4 or 2 3 64 96 现在我正在使用这样的东西 public c
  • 在 Android AudioTrack 中使用缓冲区

    我试图弄清楚如何使用缓冲区音轨 http developer android com reference android media AudioTrack html有效地传输音乐 我知道您可以使用以下命令对音频进行排队write http
  • Mercurial - 比较本地和远程存储库?

    在Git中 有这样的命令 git remote show
  • 从数据集中完全删除一行

    我的网格视图上有一个删除按钮 单击删除按钮时 该行应该是 完全从会话中删除 我目前正在做以下事情 protected void gvMainLog RowCommand Object sender GridViewCommandEventA
  • MESI协议中的L3$角色是什么

    我想了解intel Broadwell中MESI的更多细节 假设一个cpu插槽有6个核心 core 0 到 core 5 他们每个人都有自己的 L1 和 L2 并共享 L3 共享内存中有一个var X x位于cache line 称为 XC
  • C `clock()` 函数只返回一个零

    The C clock 函数只返回一个零 我尝试使用不同的类型 但没有任何改进 这是一种高精度测量时间的好方法吗 include
  • 正则表达式:匹配第一个下划线之前的所有内容以及之后的所有内容

    我有这样的表情 test abc HelloWorld there could be more here 我想要一个采用第一个单词的正则表达式before第一个下划线 所以得到 test I tried A Za z 1 但这没有用 然后我
  • 如何全局安装ESlint?

    我正在尝试安装 ESlint 以将其与 Sublime Text 2 一起用于我的所有本地项目 配置文档 https eslint org docs user guide getting started global installatio
  • 重写泛型类的方法时发生名称冲突

    我试图理解使用以下代码得到的名称冲突错误 import java util import javax swing class Foo
  • 删除截断行末尾的字形

    当在启用了截断行的终端中使用 Emacs 23 时 Emacs 会在每行末尾添加一个美元符号 指示文本继续超出屏幕边缘 这让我很困扰 我想禁用此功能或以某种方式隐藏美元符号 这可能吗 如果是的话会怎样做 尝试用这个 set display
  • 2D 基本运动 UNITY

    目前我的角色在键盘上完美运行 但是当我通过 3 个 UI 按钮将你的动作转换为触摸时 我也尝试过 UI 图像 但成功了 我没有成功 它基本上是向右 向左 跳跃 应该如何做才能使其遵循以下说明 当用户按下方向键时 角色不会停止行走 直到用户释
  • C/C++编译器反馈优化

    有没有人看到过不同程序的真实世界数字 这些程序使用 C C 编译器提供的反馈优化来支持分支预测 缓存预加载功能等 我搜索了它 令人惊讶的是 即使是流行的解释器开发小组似乎也没有检查过效果 将 ruby python php 等性能提高 10
  • Kafka-node突然从偏移量0开始消费

    有时 kafka node 消费者从偏移量 0 开始消费 而其默认行为是仅消费较新的消息 然后它不会切换回默认行为 您知道如何解决这个问题以及会发生什么以及其行为突然发生变化吗 代码非常简单 并且无需更改代码即可完成此操作 var kafk
  • 实体框架 4 的存储库模式

    我曾经使用带有存储库接口的 NHibernate 在 EF 中使用此模式的正确方法是什么 我如何实现这个存储库接口RepositoryBase
  • 打开 Word 文档并使用 PowerShell 指定编码

    我试图告诉 PowerShell 打开一个文本文件并选择某个编码选项 默认情况下 在 Word 中手动打开此文本文件时 它会尝试使用日语编码打开它 因此无法正确显示某些字符 我尝试了很多不同的方法 但没有任何效果 所以我完全陷入困境 该文本
  • 如何展平嵌套 div 以在 CSS 网格中显示它们?

    我从一个应该有两列宽的对象生成一个表 使用 vue js 每列都来自对象的键和值 这相当于以下实际 HTML div div div this is something long on the first row div div short
  • 如何在 C 程序中将日志逻辑与业务逻辑分离?那么在 C++ 中呢?

    我目前正在使用 C 进行编码 并且有很多 printf 以便有时可以跟踪应用程序的流程 问题是 有时我想要比其他人更多的细节 所以我通常花时间注释 取消注释我的 C 代码 这样我就可以获得适当的输出 使用 Java 或 C 时 我通常可以使
  • Rust:从 std::Rc 智能指针向量实现迭代器

    我从 Rust 开始 我已经面临数据所有权的问题 我想实现一个名为的通用结构Port