如何升级我的 Slicable 特性以满足重复调用中的借用检查器

How do I upgrade my Slicable trait to satisfy the borrow checker in repeated calls

我有一个 IO 库,它有一个很大的 State 结构,我正在编写一个需要两个阶段的函数。 在第一阶段,只有 reader class 被触及,但调用站点选择一个只读的 table 切片传入。

在第二阶段,修改了整个 State 结构,但不再需要只读 table。

我已将该函数拆分为两个函数——这可行,但是当我尝试组合这些函数时,当我将具体的 Vector class 替换为自定义特征 Slicable

有什么方法可以让 process_with_table_fn 对 State 结构中的 Slicable 值进行操作,而不是直接对 Vectors 进行操作?

tl;dr 我想要 fn what_i_want_to_work 编译,但我只得到 what_works 来构建。我对 Slicable 的特征定义是否针对此用例设计不当?为什么具体类型比特征更好?

pub struct MemReader {
    buf : [u8; 1024],
    off : usize,
}
pub struct Vector<'a> {
   buf : &'a [u32],
}
trait Slicable {
   fn slice(self : &Self) -> &[u32];

}
impl<'a> Slicable for Vector<'a> {
   fn slice(self : &Self) -> &[u32]{
       return self.buf;
   }
}
impl MemReader {
    fn read(self : &mut Self, how_much : usize, output : &mut u8) -> bool {
        if self.off + how_much > self.buf.len() {
            return false;
        }
        self.off += how_much;
        *output = self.buf[self.off - 1];
        return true;
    }
}

pub struct State<'a> {
   pub mr : MemReader,
   pub translation_tables : [Vector<'a>; 4],
   pub other_tables : [Vector<'a>; 4],
   pub state : i32,
}

fn process_first(mr : &mut MemReader, table : &[u32]) -> (bool, u32) {
    let mut temp : u8 = 0;
    let ret = mr.read(8, &mut temp);
    if !ret {
        return (false, 0);
    }
    return (true, table[temp as usize]);
}

fn process_second(s : &mut State, ret_index : (bool, u32), mut outval : &mut u8) -> bool {
    let (ret, index) = ret_index;
    if ! ret {
        return false;
    }
    s.state += 1;
    return s.mr.read(index as usize, &mut outval);
}

pub fn process_with_table_fn(mut s : &mut State, table : &[u32], mut outval : &mut u8) -> bool {
    let ret = process_first(&mut s.mr, table);
    return process_second(&mut s, ret, &mut outval);
}

macro_rules! process_with_table_mac(
    ($state : expr, $table : expr, $outval : expr) => {
        process_second(&mut $state, process_first(&mut $state.mr, &$table), &mut $outval)
    };
);

pub fn what_works(mut s : &mut State) {
   let mut outval0 : u8 = 0;
   let _ret0 = process_with_table_fn(&mut s, &s.other_tables[2].buf[..], &mut outval0);
}

/*
pub fn what_i_want_to_work(mut s : &mut State) {
   let mut outval0 : u8 = 0;
   let ret0 = process_with_table_fn(&mut s, s.other_tables[2].slice(), &mut outval0);

   // OR

   let mut outval1 : u8 = 0;
   //let ret1 = process_with_table_mac!(s, s.other_tables[2].slice(), outval1);
}
*/


fn main() {

}

有两件事正在发生。让我们先看看你的特征实现:

impl<'a> Slicable for Vector<'a> {
   fn slice(self : &Self) -> &[u32]{
       return self.buf;
   }
}

方法的签名扩展为

fn slice<'b>(self : &'b Self) -> &'b[u32]

这意味着生成的切片的生命周期比 self 的生命周期短。在调用站点,这意味着 s.other_tables[2].slice() 借用了 s&s.other_tables[2].buf[..] 借用了具有生命周期 'a 的东西,完全忽略了 s 的生命周期。要复制此行为,您可以为特征添加生命周期:

trait Slicable<'a> {
   fn slice(self: &Self) -> &'a [u32];
}

impl<'a> Slicable<'a> for Vector<'a> {
   fn slice(self: &Self) -> &'a [u32] {
       self.buf
   }
}

现在你应该设置好了,但是编译器在方法调用生命周期方面仍然有一个小限制,所以你需要将你的调用分成两行:

let slice = s.other_tables[2].slice();
let ret0 = process_with_table_fn(&mut s, slice, &mut outval0);