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

时间:2015-07-11 21:52:56

标签: rust

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

  

src \ main.rs:89:9:89:36错误:类型不匹配解析for<'r> <[closure src\ma in.rs:75:33: 88:10] as core::ops::FnOnce<(u32, gpb::definitions::WireType, &'r collections::vec::Vec<u8>, usize)>>::Output == usize:    预期的生命周期参数,       发现混凝土寿命[E0271]   src \ main.rs:89 gpb :: decoding :: read_message(source,field_handler);

即使阅读了有关lifetimes等的3篇文章章节。人。我没有遇到“具体的生命周期”这个术语,因此无法弄清楚这个错误与哪些代码有关。闭包本身,一个或多个参数,返回码?关闭传递给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) - &gt;调用n次:field_handler
  • 退出范围。

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

1 个答案:

答案 0 :(得分:7)

首先,如果您想快速回答,您应该花一些精力编写一个最小的,可编译的示例,这样人们就不必猜测潜在的解决方案是否会起作用。像这样:

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!();
}

此答案的其余部分基于以上出现以复制您的问题:

error[E0631]: type mismatch in closure arguments
  --> src/lib.rs:11:5
   |
4  |     let mut field_handler = |tag, wire_type, source, position| -> usize {
   |                             ------------------------------------------- found signature of `fn(u32, WireType, &std::vec::Vec<u8>, usize) -> _`
...
11 |     read_message(source, field_handler);
   |     ^^^^^^^^^^^^ expected signature of `for<'r> fn(u32, WireType, &'r std::vec::Vec<u8>, usize) -> _`
   |
note: required by `read_message`
  --> src/lib.rs:14:1
   |
14 | / fn read_message<F>(source: &Vec<u8>, field_handler: F)
15 | | where
16 | |     F: Fn(u32, WireType, &Vec<u8>, usize) -> usize,
17 | | {
18 | |     panic!();
19 | | }
   | |_^

error[E0271]: type mismatch resolving `for<'r> <[closure@src/lib.rs:4:29: 10:6] as std::ops::FnOnce<(u32, WireType, &'r std::vec::Vec<u8>, usize)>>::Output == usize`
  --> src/lib.rs:11:5
   |
11 |     read_message(source, field_handler);
   |     ^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
   |
note: required by `read_message`
  --> src/lib.rs:14:1
   |
14 | / fn read_message<F>(source: &Vec<u8>, field_handler: F)
15 | | where
16 | |     F: Fn(u32, WireType, &Vec<u8>, usize) -> usize,
17 | | {
18 | |     panic!();
19 | | }
   | |_^

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

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函数只是让编译器确定闭包的类型,允许以后使用(或不使用)。