我有一个 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/