首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用从临时数组中添加的数据返回链迭代器?

如何使用从临时数组中添加的数据返回链迭代器?
EN

Stack Overflow用户
提问于 2021-01-15 16:00:24
回答 1查看 263关注 0票数 2

我正在编写一个MQTT5库。要发送数据包,在编写有效负载之前,我需要知道有效负载的大小。我确定大小的解决方案按重要性排序如下:

maintain

  • should容易创建
  1. 不创建数据副本
  2. 应该是公平的(避免双重计算)

要确定大小,我可以执行以下任何一种解决方案:

如果不创建包装类型( annoying

  • hold ),则
  1. 手工完成计算,这是要发送内存的数据副本,我希望避免
  2. 为包含std::iter::Chain本身的有效负载构建std::iter::ExactSizeIterator

我决定使用第3版。

下面的示例显示了我编写MQTT字符串迭代器的尝试。MQTT字符串由两个字节组成,这两个字节是字符串的长度,后面是数据作为utf8。

代码语言:javascript
复制
use std::iter::*;
use std::slice::Iter;

pub struct MQTTString<'a> {
    chain: Chain<Iter<'a, u8>, Iter<'a, u8>>,
}

impl<'a> MQTTString<'a> {
    pub fn new(s: &'a str) -> Self {
        let u16_len = s.len() as u16;
        let len_bytes = u16_len.to_be_bytes();
        let len_iter = len_bytes.iter(); // len_bytes is borrowed here

        let s_bytes = s.as_bytes();
        let s_iter = s_bytes.iter();

        let chain = len_iter.chain(s_iter);

        MQTTString { chain }
    }
}

impl<'a> Iterator for MQTTString<'a> {
    type Item = &'a u8;
    fn next(&mut self) -> Option<&'a u8> {
        self.chain.next()
    }
}

impl<'a> ExactSizeIterator for MQTTString<'a> {}

pub struct MQTTStringPait<'a> {
    chain: Chain<std::slice::Iter<'a, u8>, std::slice::Iter<'a, u8>>,
}

这个实现没有编译,因为我借用了len_bytes而不是移动它,所以在Chain使用它之前它会被删除:

代码语言:javascript
复制
error[E0515]: cannot return value referencing local variable `len_bytes`
  --> src/lib.rs:19:9
   |
12 |         let len_iter = len_bytes.iter(); // len_bytes is borrowed here
   |                        --------- `len_bytes` is borrowed here
...
19 |         MQTTString { chain }
   |         ^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

有什么好办法吗?将len_bytes添加到MQTTString结构没有帮助。是否有更好的第四种办法来解决这个问题?

EN

回答 1

Stack Overflow用户

发布于 2021-01-15 16:37:12

根本问题是iter借用了数组。在夜间锈蚀中,可以使用array::IntoIter,但确实需要更改迭代器以返回u8而不是&u8

代码语言:javascript
复制
#![feature(array_value_iter)]

use std::array::IntoIter;
use std::iter::*;
use std::slice::Iter;

pub struct MQTTString<'a> {
    chain: Chain<IntoIter<u8, 2_usize>, Copied<Iter<'a, u8>>>,
}

impl<'a> MQTTString<'a> {
    pub fn new(s: &'a str) -> Self {
        let u16_len = s.len() as u16;
        let len_bytes = u16_len.to_be_bytes();
        let len_iter = std::array::IntoIter::new(len_bytes);

        let s_bytes = s.as_bytes();
        let s_iter = s_bytes.iter().copied();

        let chain = len_iter.chain(s_iter);

        MQTTString { chain }
    }
}

impl<'a> Iterator for MQTTString<'a> {
    type Item = u8;
    fn next(&mut self) -> Option<u8> {
        self.chain.next()
    }
}

impl<'a> ExactSizeIterator for MQTTString<'a> {}

通过使用Vec,您可以在“稳定锈蚀”中做同样的事情,但这可能有点过分。相反,由于您知道数组的确切大小,所以可以获取值并进行更多的链接:

代码语言:javascript
复制
use std::iter::{self, *};
use std::slice;

pub struct MQTTString<'a> {
    chain: Chain<Chain<Once<u8>, Once<u8>>, Copied<slice::Iter<'a, u8>>>,
}

impl<'a> MQTTString<'a> {
    pub fn new(s: &'a str) -> Self {
        let u16_len = s.len() as u16;
        let [a, b] = u16_len.to_be_bytes();

        let s_bytes = s.as_bytes();
        let s_iter = s_bytes.iter().copied();

        let chain = iter::once(a).chain(iter::once(b)).chain(s_iter);

        MQTTString { chain }
    }
}

impl<'a> Iterator for MQTTString<'a> {
    type Item = u8;
    fn next(&mut self) -> Option<u8> {
        self.chain.next()
    }
}

impl<'a> ExactSizeIterator for MQTTString<'a> {}

另请参阅:

从纯效率的角度来看,&u8的迭代器不是一个好主意。在64位系统中,&u8占用64位,而u8本身占用8位。此外,在逐字节的基础上处理这些数据可能会阻碍围绕复制内存进行的常见优化。

相反,我建议创建一些可以将自身写入实现Write的东西。一个可能的执行:

代码语言:javascript
复制
use std::{
    convert::TryFrom,
    io::{self, Write},
};

pub struct MQTTString<'a>(&'a str);

impl MQTTString<'_> {
    pub fn write_to(&self, mut w: impl Write) -> io::Result<()> {
        let len = u16::try_from(self.0.len()).expect("length exceeded 16-bit");
        let len = len.to_be_bytes();
        w.write_all(&len)?;
        w.write_all(self.0.as_bytes())?;
        Ok(())
    }
}

另请参阅:

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65739365

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档