read_file()的奇思妙想(续)

read_file()的奇思妙想(续)

read_file() 代码实现:
pub fn read_file(path: &str) -> Result<Vec<u8>, Box<dyn std::error::Error + 'static>> {
    // 读文件
    let vec_u8_file_stream = fs::read(path)?;
    // 消除空格和换行符
    let r:Vec<u8> = vec_u8_file_stream.into_iter()	//在此处vec_u8_file_stream不再有效,被转化成了迭代器了
        .filter(|&x| !x.is_ascii_whitespace() && !x.is_ascii_control())
        .collect::<Vec<u8>>();
    Ok(r)
}
A. 直接在 vec_u8_file_stream 上操作,并且返回其处理后的引用?

在 Rust 中,直接在 vec_u8_file_stream 上操作并返回其处理后的引用是不可能的,因为 vec_u8_file_stream 是一个局部变量,其生命周期仅限于 read_file 函数内部。一旦函数结束,vec_u8_file_stream 将被销毁,任何指向它的引用都将变得无效。

如果想要在函数外部使用处理后的数据,必须返回数据的所有权,而不是引用。这意味着应该返回 Vec<u8> 而不是 &[u8]。这样,数据的所有权会从函数传递到调用者,确保数据在函数外部仍然有效。

如果你的需求是在函数内部创建数据,并希望在函数外部以引用的形式访问这些数据,你需要考虑数据的生命周期管理。通常,这涉及到使用如 Box, Rc, 或 Arc 等智能指针,或者将数据存储在更高级别的结构中,这些结构负责管理数据的生命周期。

以下是一个示例,展示如何使用 Box 来返回一个在堆上分配的 Vec<u8>,从而可以在函数外部安全地引用它:

pub fn read_file(path: &str) -> Result<Box<Vec<u8>>, Box<dyn std::error::Error + 'static>> {
    let vec_u8_file_stream = fs::read(path)?;
    let r: Vec<u8> = vec_u8_file_stream.into_iter()
        .filter(|&x| !x.is_ascii_whitespace() && !x.is_ascii_control())
        .collect::<Vec<u8>>();

    Ok(Box::new(r))
}

🗝️在这个修改后的版本中,r 被封装在一个 Box 中,这意味着它在堆上分配,并且其所有权被返回给函数的调用者。这样,调用者就可以持有一个指向堆上数据的引用,而不用担心数据会在函数结束时被销毁。

A.a 是返回 Vec<u8> 性能高还是返回 Box<Vec<u8>> 性能高?

在 Rust 中,Vec<u8>Box<Vec<u8>> 的性能差异主要取决于使用场景。以下是两者的一些比较:

  1. 内存分配:
    Vec<u8>Box<Vec<u8>> 都在堆上分配内存。Vec<u8> 直接管理其数据的内存,而 Box<Vec<u8>> 是一个额外的指针层,指向 Vec<u8>

    Box<Vec<u8>> 在返回大型数据结构时可能稍微快一点,因为它只移动一个指针,而不是整个 Vec<u8> 数据结构。这在返回非常大的 Vec<u8> 时尤其明显。

  2. 数据访问:
    Vec<u8> 提供直接访问其元素的能力,而 Box<Vec<u8>> 需要先解引用。这意味着对于频繁访问元素的情况,Vec<u8> 可能会更快一些。

  3. 函数返回类型:
    如果函数的返回类型是 Box<Vec<u8>>,这意味着返回的 Vec<u8> 被装箱在一个 Box 中。这种情况下,Box 本身几乎没有运行时开销,但它确实增加了一个间接层。

    返回 Vec<u8> 可以直接使用,而无需额外的解引用步骤。

  4. 缓存局部性:

    Vec<u8> 由于数据通常是连续存储的,所以在内存中的缓存局部性通常更好。

    Box<Vec<u8>> 添加了一个间接层,可能会略微影响缓存效率,尤其是在频繁访问数据时。

总的来说,如果你的函数需要返回大型的 Vec<u8> 并且这个向量在函数之外的生命周期很长,使用 Box<Vec<u8>> 可能会略微提高性能,因为它减少了数据的复制。然而,对于小型数据或频繁访问数据的情况,直接返回 Vec<u8> 可能更为高效。

在实际应用中,这两种方法的性能差异可能非常小,选择哪一种更多的是基于具体需求和代码的可读性考虑。

B. 想函数中返回一个引用应该如何写?

🗝️在 Rust 中,如果你想要从函数中返回一个引用,你需要确保引用的生命周期足够长,这通常意味着它不能是一个局部变量的引用。然而,有一些方法可以在 Rust 中安全地返回局部数据的引用,但这通常涉及到改变数据的所有权或使用特定的数据结构来管理生命周期。

以下是一些可能的方法:

  1. 返回拥有数据的结构体:

如果你想返回一个数据片段的引用,你可以创建一个包含数据和引用的结构体。这样,数据和引用就被同一个结构体拥有,因此可以安全地管理它们的生命周期。

   struct OwnedData {
       data: Vec<u8>,
       slice: std::ops::Range<usize>,
   }

   impl OwnedData {
       fn new(mut data: Vec<u8>, start: usize, end: usize) -> Self {
           assert!(start <= end && end <= data.len());
           OwnedData {
               slice: start..end,
               data,
           }
       }

       fn get_slice(&self) -> &[u8] {
           &self.data[self.slice.clone()]
       }
   }

   fn create_data() -> OwnedData {
       let data = vec![1, 2, 3, 4, 5];
       OwnedData::new(data, 1, 3)
   }
  1. 使用持续传递风格(Continuation Passing Style, CPS):

你可以定义一个接受闭包作为参数的函数,该闭包在函数内部使用数据。这样,你可以避免返回引用,而是在数据的有效范围内使用数据。

   fn with_data<F, R>(f: F) -> R
   where
       F: FnOnce(&[u8]) -> R,
   {
       let data = vec![1, 2, 3, 4, 5];
       f(&data[1..3])
   }

   fn main() {
       let result = with_data(|slice| {
           // 在这里使用 slice
           slice.len()
       });
       println!("Length of slice: {}", result);
   }

🗝️这些方法各有优缺点,选择哪种方法取决于你的具体需求和上下文。如果你需要在函数外部长时间持有数据引用,第一种方法可能更适合;如果你只是需要临时访问数据,第二种方法可能更简洁。

B.a 上面的闭包是什么😧😧

为啥冒出了这么多奇奇怪怪的东西❓❓❓见过好像又没见过😅😅

B.b 迭代器的filter返回什么❓

在 Rust 中,Iteratorfilter 方法返回一个 Filter 迭代器。这个 Filter 迭代器包装了原始迭代器,并在迭代过程中应用一个指定的谓词(predicate)函数来决定哪些元素应该被包含在新的迭代结果中。

具体来说,filter 方法的签名如下:

fn filter<P>(self, predicate: P) -> Filter<Self, P> where
    Self: Sized,
    P: FnMut(&Self::Item) -> bool,

这里:

  • Self 是原始迭代器的类型。

  • P 是一个谓词函数,它接受一个对迭代器元素的引用,并返回一个布尔值,指示该元素是否应该包含在结果迭代器中。

  • 返回的 Filter 类型是一个结构体,它实现了 Iterator trait,其 Item 类型与原始迭代器相同。

使用 filter 方法的一个例子如下👇:

let nums = vec![1, 2, 3, 4, 5];
let even_nums: Vec<_> = nums.iter().filter(|&&x| x % 2 == 0).collect();
println!("{:?}", even_nums); // 输出: [2, 4]

🗝️在这个例子中,filter 方法接受一个闭包,该闭包检查每个元素是否是偶数,并返回一个新的 Filter 迭代器,该迭代器只包含满足条件的元素。

本站中有一部分来源于网络和媒体的内容(文章、源码、软件应用、资源附件等),并尽可能的标出参考来源、出处,本站尊重原作者的成果,若本站内容侵犯了您的合法权益时或者对转载内容有疑义的内容原作者,请书面反馈并提供确切的个人身份证明与详细资料信息在第一时间以邮件形式进行联系沟通;

  • 35
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

憨七龟777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值