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

时间:2019-03-03 11:14:05

标签: rust slice

我一直把头撞在墙上,试图弄清楚如何管理同一较大切片的多个切片。我这样做的主要动机是,首先要有一个很大的切片,然后逐渐使用越来越小的子切片,直到该子切片仅包含一个元素。

从高层的角度来看,我不明白为什么不能做到这一点,因为我不需要移动或变异原始切片。我只需要切片的多个视图以及与原始切片相同的生存期。

为说明起见,请参考下图:

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

2 个答案:

答案 0 :(得分: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 :(得分:0)

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

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

这在时间上与split_queue的长度成比例。您可能希望将Vec替换为VecDeque及其常量方法pop_frontpush_front