rust 共享来自可变方法的引用

atmip9wb  于 2023-01-02  发布在  其他
关注(0)|答案(2)|浏览(150)

Rust不允许借用多个可变引用。我理解这一点。但是我找不到任何优雅的方法来实现一些算法。下面是这样一个算法的简化版本。Ladder结构体分发不断增加的数字序列的切片,例如[0][0, 1][0, 1, 2]等等。

struct Ladder {
    position: usize,
    data: [u8; 10],
}

impl Ladder {
    fn get_next(&mut self) -> &[u8] {
        self.position += 1;

        &(self.data[0..self.position])
    }
    
    fn new() -> Ladder {
        Ladder {
            position: 0,
            data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        }
    }
}

我需要调用get_next()几次,收集返回的序列并调用一个闭包来处理这些序列。

fn test_ladder(consumer: impl Fn(&[&[u8]])) {
    let mut l = Ladder::new();
    let mut steps: [&[u8]; 3] = [&[]; 3];

    steps[0] = l.get_next();
    steps[1] = l.get_next();
    steps[2] = l.get_next();

    consumer(&steps);
}

fn main() {
    test_ladder(|steps| {
        for seq in steps {
            println!("{:?}", *seq);
        }
    });
}

这是一个非分配算法。我不能使用std::Vec
处理这类问题的惯用方法是什么?

sg3maiej

sg3maiej1#

这里的问题是你不能保留对你变异的东西的引用,而.get_next()被允许变异data,你需要做的是把数据和变异分开,你可以只保留对原始数据的引用。
创建一个元素序列听起来很像迭代器,下面是一个例子:

struct LadderIter<'a> {
    position: usize,
    data: &'a [u8],
}

impl<'a> LadderIter<'a> {
    fn new(data: &'a [u8]) -> LadderIter<'a> {
        LadderIter { position: 0, data }
    }
}

impl<'a> Iterator for LadderIter<'a> {
    type Item = &'a [u8];
    
    fn next(&mut self) -> Option<Self::Item> {
        if self.position == self.data.len() {
            None
        } else {
            self.position += 1;
            Some(&self.data[0..self.position])
        }
    }
}

然后可以将其用作迭代器:
x一个一个一个一个x一个一个二个x
或者在您的特定使用情形中:

let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut ladder = LadderIter::new(&data);
let steps: [&[u8]; 3] = [
    ladder.next().unwrap(),
    ladder.next().unwrap(),
    ladder.next().unwrap(),
];
stszievb

stszievb2#

另一种方法是使用内部可变性,因为您只修改position,所以可以使用零成本Cell

use std::cell::Cell;

struct Ladder {
    position: Cell<usize>,
    data: [u8; 10],
}

impl Ladder {
    fn get_next(&self) -> &[u8] {
        self.position.set(self.position.get() + 1);

        &self.data[0..self.position.get()]
    }
    
    fn new() -> Ladder {
        Ladder {
            position: Cell::new(0),
            data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        }
    }
}

相关问题