rust - 管理同一内存段的多个切片

标签 rust slice

我一直在用头撞墙试图弄清楚如何管理同一个较大切片的多个切片。我这样做的主要动机是我从一些大切片开始,然后逐渐处理越来越小的子切片,直到子切片只包含一个元素。

从高层次的角度来看,我不清楚为什么不能这样做,因为我不需要移动或改变原始切片。我只需要与原始切片具有相同生命周期的切片的多个 View 。

为了说明,请引用此图:

Memory Model

原始切片是绿色的,往下每一层表示尺寸越来越小的切片,直到切片中只有一个元素。我想要的是确保每个切片的元素的生命周期“到达”原始切片,而不依赖于它上面的切片的生命周期。我在一个 while 循环中使用这些切片,并将每个切片存储在一个队列中,该队列在循环期间持续存在。

我遇到的问题是切片“生命周期不够长”,但我不太明白为什么会这样。

由于每个切片仅引用原始切片,是否可以将这些切片作为“拥有的切片”而不是新向量存储在队列中?性能甚至有差异吗?将切片边界的索引存储在队列中以备后用会更好吗?感谢您提供任何帮助,谢谢。

下面是一些精确演示问题的代码:

pub struct Split<'a> {
    pub first_half: &'a [&'a [u8]],
    pub second_half: &'a [&'a [u8]],
}

impl<'a> Split<'a> {
    pub fn new(first_half: &'a [&'a [u8]], second_half: &'a [&'a [u8]]) -> Split<'a> {
        Self {
            first_half,
            second_half,
        }
    }
}

fn make_smaller_slice<'a>(slice: &'a [&'a [u8]]) -> Vec<&'a [u8]> {
    let mut smaller_slice = Vec::with_capacity(slice.len());
    for elem in slice {
        if true {
            smaller_slice.push(*elem)
        }
    }

    smaller_slice
}

fn main() {
    let mut original_data = Vec::with_capacity(100);
    for i in 0..100 {
        original_data.push(vec![i]);
    }
    let original_slice = original_data
        .iter()
        .map(|x| x.as_slice())
        .collect::<Vec<_>>();
    let mut split_queue = vec![];
    split_queue.push(Split::new(&original_slice[0..50], &original_slice[50..100]));
    loop {
        let split = split_queue.remove(0);
        let first_half = split.first_half.split_at(split.first_half.len() / 2);

        let processed_first_half_0 = make_smaller_slice(&first_half.0);
        let processed_first_half_1 = make_smaller_slice(&first_half.1);

        let first_split = Split::new(&processed_first_half_0, &processed_first_half_1);
        split_queue.insert(0, first_split);
    }
}

以及由此产生的错误:

error[E0597]: `processed_first_half_0` does not live long enough
  --> src/main.rs:44:38
   |
38 |         let split = split_queue.remove(0);
   |                     ----------- borrow used here, in later iteration of loop
...
44 |         let first_split = Split::new(&processed_first_half_0, &processed_first_half_1);
   |                                      ^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
45 |         split_queue.insert(0, first_split);
46 |     }
   |     - `processed_first_half_0` dropped here while still borrowed

error[E0597]: `processed_first_half_1` does not live long enough
  --> src/main.rs:44:63
   |
38 |         let split = split_queue.remove(0);
   |                     ----------- borrow used here, in later iteration of loop
...
44 |         let first_split = Split::new(&processed_first_half_0, &processed_first_half_1);
   |                                                               ^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
45 |         split_queue.insert(0, first_split);
46 |     }
   |     - `processed_first_half_1` dropped here while still borrowed

最佳答案

修改 make_smaller_slice 以返回对切片而不是向量的引用可解决该问题。

pub struct Split<'a> {
    pub first_half: &'a [&'a [u8]],
    pub second_half: &'a [&'a [u8]]
}

impl<'a> Split<'a> {
    pub fn new(first_half: &'a [&'a [u8]], second_half: &'a [&'a [u8]]) -> Split<'a> {
        Self {
            first_half,
            second_half
        }
    }
}

fn make_smaller_slice<'a>(slice: &'a [&'a [u8]]) -> &'a[&'a [u8]] {
    let mut start_bound = 0;
    for i in 0..slice.len() {
        if true {
            start_bound = i;
        } 
    }

    &slice[start_bound..]
}

fn main() {
    let mut original_data = Vec::with_capacity(100);
    for i in 0..100 {
        original_data.push(vec![i]);
    }
    let original_slice = original_data.iter().map(|x| x.as_slice()).collect::<Vec<_>>();
    let mut split_queue = vec![];
    split_queue.push(Split::new(&original_slice[0..50], &original_slice[50..100]));
    loop {
        let split = split_queue.remove(0);
        let first_half = split.first_half.split_at(split.first_half.len() / 2);

        let processed_first_half_0 = make_smaller_slice(&first_half.0);
        let processed_first_half_1 = make_smaller_slice(&first_half.1);

        let first_split = Split::new(&processed_first_half_0, &processed_first_half_1);
        split_queue.insert(0, first_split);
    }
}

感谢来自 Reddit 的 _TheDust_。

关于rust - 管理同一内存段的多个切片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54968221/

相关文章:

rust - `FnOnce` 的实现对于异步递归来说不够通用

rust - 当我可以绑定(bind)可变变量时,为什么还需要重新绑定(bind)/隐藏?

arrays - Go 中这两种 "slice copy"方法有什么区别

html - 使用CSS在浏览器中绘制部分图像

python - (Python) 列表中切片函数的行为

rust - 使用 Hyper 的 Rust 客户端证书

generics - 为两步从创建通用的“从/到”快捷方式

rust - 从模块访问外部 crate

python - 如何使用显式 "slice of s from i to j with step k"反转字符串?

go - 计算 sha256 在附加 slice 后会给出不同的结果,具体取决于我之前是否打印出 slice