如何编译?
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);
}
答案 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() }
可以做到这一点,但我不知道有什么方法可以做到这一点。