首页 文章

预期的约束寿命参数,找到具体的寿命[E0271]

提问于
浏览
1

虽然下面的代码是一个早期的原型,并且不要过于认真地考虑我在这个阶段如何实现协议缓冲区,但是我无法理解生锈编译器带来的错误信息 .

src \ main.rs:89:9:89:36错误:类型不匹配解析为<r> <[闭合src \ ma in.rs:75:33:88:10]为核心:: ops :: FnOnce <(u32,gpb :: definitions :: WireType,&'r collections :: vec :: Vec <u8>,usize)>> :: Output == usize:expected bound lifetime参数,找到具体的生命周期[E0271] src \ main.rs:89 gpb :: decoding :: read_message(source,field_handler);

即使在阅读了有关lifetimes等的3篇文章章节之后 . 人 . 我没有遇到"concrete lifetime"一词,因此无法弄清楚这个错误与哪些代码有关 . 闭包本身,一个或多个参数,返回码?关闭的通过 read_message() ? ...

main.rs片段

fn from_gpb( source : &Vec<u8>) -> TimeMessage {
    fn init_vec_u64( count : usize, init_value : u64) -> Vec<u64> {
        let mut result = Vec::<u64>::with_capacity(count);
        for i in 0..count {
            result.push(init_value);
        }
        result
    }
    let mut message_id : u32 = 0;
    let mut times_sec  = init_vec_u64(4,0u64);
    let mut times_usec = init_vec_u64(4,0u64);
    let mut max_time_index = 0;
    let mut time_index = | index | { if max_time_index < index { max_time_index = index;}};
    let mut field_handler = |tag,wire_type,source,position| -> usize {
        match (tag,wire_type) {
            (1u32,gpb::definitions::WireType::Varint) => {let (v,p) = gpb::decoding::read_varint32(source,position); message_id = v; p},
            (2u32,gpb::definitions::WireType::Fixed64) => {let (sec,p) = gpb::decoding::read_fixed64(source,position); times_sec[0] = sec; time_index(0); p},
            (3u32,gpb::definitions::WireType::Fixed64) => {let (usec,p) = gpb::decoding::read_fixed64(source,position); times_usec[0] = usec; time_index(0); p},
            (4u32,gpb::definitions::WireType::Fixed64) => {let (sec,p) = gpb::decoding::read_fixed64(source,position); times_sec[1] = sec; time_index(1);p},
            (5u32,gpb::definitions::WireType::Fixed64) => {let (usec,p) = gpb::decoding::read_fixed64(source,position); times_usec[1] = usec; time_index(1);p},
            (6u32,gpb::definitions::WireType::Fixed64) => {let (sec,p) = gpb::decoding::read_fixed64(source,position); times_sec[2] = sec; time_index(2);p},
            (7u32,gpb::definitions::WireType::Fixed64) => {let (usec,p) = gpb::decoding::read_fixed64(source,position); times_usec[2] = usec; time_index(2); p},
            (8u32,gpb::definitions::WireType::Fixed64) => {let (sec,p) = gpb::decoding::read_fixed64(source,position); times_sec[3] = sec; time_index(3); p},
            (9u32,gpb::definitions::WireType::Fixed64) => {let (usec,p) = gpb::decoding::read_fixed64(source,position); times_usec[3] = usec; time_index(3); p},
            (_,_) => panic!("Invalid field tag/wire_type combination!") // TODO: change the panic to a gpb::decoding::skip(..) call.
        }
    };
    gpb::decoding::read_message( source, field_handler );
    let mut make_times = || -> Vec<prectime::PrecTime> {
        let time_count = max_time_index+1;
        let mut times = Vec::<prectime::PrecTime>::with_capacity(time_count);
        times_sec.truncate(time_count);
        times_usec.truncate(time_count);
        for i in 0..time_count {
            times.push(prectime::PrecTime { sec : times_sec[i], usec : times_usec[i]});
        }
        times               
    };
    TimeMessage { id : message_id, times : make_times() }    
}

gpb.rs片段

pub fn read_message<F>( source : &Vec<u8>, field_handler : F) where F: Fn(u32,super::definitions::WireType, &Vec<u8>, usize) -> usize {
    let mut cursor = 0;
    while cursor < source.len() {
        let (tag_and_wire_type, position) = read_varint32( source, cursor );
        let wt = super::definitions::wire_type_from_value( tag_and_wire_type & 0x07u32 );
        let tag = (tag_and_wire_type >> 3);
        let new_pos = field_handler(tag,wt, source,position);
        cursor = new_pos;
    }
}

代码的作用摘要:

  • 定义field_handler函数

  • read_message(data,field_handler) - >调用n次:field_handler

  • 退出范围 .

任何事情(闭包,调用,向量,field_handler写入 from_gpb() 上下文,......)都是在 from_gpb() 函数中定义的,我根本不明白生命周期如何成为一个问题 . 有关生命周期的所有信息都应该可供编译器使用 .

1 回答

  • 7

    首先,如果你想快速回答,你应该付出一些努力来编写一个最小的,可编译的例子,这样人们就不必猜测一个潜在的解决方案是否会起作用 . 像这样:

    fn main() {}
    
    enum WireType {}
    
    fn from_gpb(source: &Vec<u8>) {
        let mut field_handler = |tag, wire_type, source, position| -> usize {
            let tag: u32 = tag;
            let wire_type: WireType = wire_type;
            let source: &Vec<u8> = source;
            let position: usize = position;
            panic!();
        };
        read_message(source, field_handler);
    }
    
    fn read_message<F>(source: &Vec<u8>, field_handler: F)
    where F: Fn(u32, WireType, &Vec<u8>, usize) -> usize {
        panic!();
    }
    

    本答案的其余部分基于上述内容,似乎可以复制您的问题 .

    最简单的方法是允许编译器正确推断闭包类型:

    fn from_gpb_closure_inference(source: &Vec<u8>) {
        read_message(source, |tag, wire_type, source, position| -> usize {
            let tag: u32 = tag;
            let wire_type: WireType = wire_type;
            let source: &Vec<u8> = source;
            let position: usize = position;
            panic!();
        });
    }
    

    当闭包直接作为函数的参数提供时,闭包推理才真正起作用 . 从理论上讲,两者应该是等价的,但事实并非如此 .

    你可以做的另一件事就是在不实际使用闭包的情况下欺骗编译器进行推理:

    fn constrain_handler<F>(f: F) -> F
    where F: Fn(u32, WireType, &Vec<u8>, usize) -> usize {
        f
    }
    
    fn from_gpb_constrain(source: &Vec<u8>) {
        let mut field_handler = constrain_handler(
            |tag, wire_type, source, position| -> usize {
                let tag: u32 = tag;
                let wire_type: WireType = wire_type;
                let source: &Vec<u8> = source;
                let position: usize = position;
                panic!();
            }
        );
        read_message(source, field_handler);
    }
    

    在这种情况下, constrain_handler 函数只是让编译器确定闭包的类型,允许以后使用它(或不使用它) .

相关问题