rust - 如何升级我的 Slicable 特征以满足重复调用中的借用检查器的要求

标签 rust traits borrow-checker

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

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

我已将函数拆分为两个函数 - 这很有效,但是当我尝试组合这些函数时,当我用自定义特征替换具体的 Vector 类时,借用检查器会崩溃可切片

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

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);

关于rust - 如何升级我的 Slicable 特征以满足重复调用中的借用检查器的要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36543836/

相关文章:

database - 检查某个数据库条目是否已存在于 DIesel/Rust 中

rust - 如何解决 "upstream crates may add a new impl of trait"错误?

c++ - 字符串的类型特征

generics - 泛型函数可以用特征参数化吗?

Rust,在迭代中需要一个可变的 Self 引用

rust - 制作使用项目字段作为键的查找表的惯用方法是什么?

rust - 使用 Iron 在简单的 Web 服务器中调用两次的函数

rust - 为什么对 `fn pop(&mut self) -> Result<T, &str>` 的调用继续借用我的数据结构?

Rust:在不可变地借用整个 HashMap 的同时修改 HashMap 中的值

generics - 限制可包装使用的模板