Как обновить черту Slicable, чтобы проверять заемные средства при повторных вызовах

У меня есть библиотека ввода-вывода с большой структурой State, и я пишу функцию, которая требует двух этапов. На первом этапе затрагивается только класс читателя, но сайт вызова выбирает доступный только для чтения срез таблицы для передачи.

На втором этапе вся структура State изменяется, но таблица только для чтения больше не нужна.

Я разделил функцию на две функции - и это работает, но когда я пытаюсь объединить эти функции, программа проверки заимствований перестает работать, когда я заменяю конкретный класс Vector пользовательским признаком Slicable

Есть ли способ заставить process_with_table_fn работать со значениями 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() {

}

person hellcatv    schedule 11.04.2016    source источник


Ответы (1)


Происходят две вещи. Давайте сначала посмотрим на реализацию вашей черты:

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);
person oli_obk    schedule 11.04.2016