如何获得对拥有对象的生命周期? (无法推断终身参数的适当寿命)

时间:2015-02-14 04:07:09

标签: rust

如何编译?

extern crate collections;
fn print_x_from_table(table: collections::BTreeMap<String, String>) {
    let x: &str = table
        .get(&String::from_str("x"))
        .map(|s: &String| &s[])  // ERROR!
        .unwrap_or("");
    println!("table contains x={}", x);
}

它给出了这个错误:

src/rusttest.rs:5:22: 5:25 error: cannot infer an appropriate lifetime for lifetime parameter 'a in function call due to conflicting requirements
src/rusttest.rs:5       .map(|s: &String| &s[])
                                           ^~~
src/rusttest.rs:7:34: 7:35 note: first, the lifetime cannot outlive the expression at 7:33...
src/rusttest.rs:7   println!("table contains x={}", x);
                                                    ^
note: in expansion of format_args!
<std macros>:2:43: 2:76 note: expansion site
<std macros>:1:1: 2:78 note: in expansion of println!
src/rusttest.rs:7:2: 7:37 note: expansion site
src/rusttest.rs:7:34: 7:35 note: ...so type `&str` of expression is valid during the expression
src/rusttest.rs:7   println!("table contains x={}", x);

如果table是参考参数,我知道我可以添加一个类型参数'a来指示s应该存在多长时间。但是当我拥有table时,我该怎么做?

extern crate collections;
fn print_x_from_ref_table<'a>(table: &'a collections::BTreeMap<String, String>) {
    let x: &'a str = table
        .get(&String::from_str("x"))
        .map(|s: &'a String| &s[])
        .unwrap_or("");
    println!("table contains x={}", x);
}

2 个答案:

答案 0 :(得分:1)

我设法通过避免使用闭包和使用匹配来使其工作。我认为这是有效的,因为在.map(|s| &s[])中,编译器会感到困惑并认为引用应该比它实际存在的时间短。

fn print_x_from_table(table: collections::BTreeMap<String, String>) {
    let x = match table.get("x") {
        Some(v) => &v[],
        None => ""
    };
    println!("table contains x={}", x);
}

答案 1 :(得分:0)

我认为这是闭包语法的限制。看看这些替代方案:

use std::ops::Deref;
use std::collections::HashMap;

fn inner<'a>(s: &'a String) -> &'a str { //'
    &s[]
}

fn inner2(s: &String) -> &str {
    &s[]
}

fn print_x_from_table(table: HashMap<String, String>) {
    let x = table
        .get("x")
        // .map(|s: &String| &s[])  // ERROR!
        // .map(inner) // OK
        // .map(inner2) // OK
        // .map(Deref::deref)  // OK
        .map(|s| &s[])  // OK
        .unwrap_or("");
    println!("table contains x={}", x);
}

fn main() {
}

在第二个例子中,我们使用一个函数inner,它具有明确的命名生命周期,将输入和输出绑定在一起,让引用超出闭包。但是,这是终身省略的确切情况,因此inner2是相同的概念,但更短。我们也可以删除中间人并直接使用Deref::deref方法。

最后一个示例没有指定任何类型,因此编译器会自动插入它们并将引用绑定在一起(最后一部分是基于观察而非内在知识的猜测)。这可能是你大部分时间都看到的;当你不需要时,指定类型并不常见。

如果我们可以在闭包定义中指定生命周期,那么一个潜在的“解决方案”就是。一种假设的语法,如

<'a>|foo: &'a String| -> &'a str { foo.bar() }

可以做到这一点,但我不知道有什么方法可以做到这一点。