管理同一部分内存的多个切片

问题描述 投票:0回答:2

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

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

为了说明,请参考此图:

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
rust slice
2个回答
0
投票

修改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_。


-1
投票

您的代码中可能存在问题。在这两行中:

let split = split_queue.remove(0);
split_queue.insert(0, first_split);

这与split_queue的长度成正比。你可能想用Vec及其恒定时间方法VecDequepop_front替换push_front

© www.soinside.com 2019 - 2024. All rights reserved.