value"活不够长",但仅限于使用函数指针时

时间:2017-12-30 23:52:51

标签: rust

我试图让以下简化代码进行编译:

type FunctionType<'input> = fn(input_string: &'input str) -> Result<(), &'input str>;

fn okay<'input>(_input_string: &'input str) -> Result<(), &'input str> {
    Ok(())
}

fn do_stuff_with_function(function: FunctionType) {
    let string = String::new();
    match function(string.as_str()) {
        Ok(_) => {},
        Err(_) => {},
    }

}

fn main() {
    do_stuff_with_function(okay);    
}

游乐场抱怨道:

error[E0597]: `string` does not live long enough
  --> src/main.rs:13:20
   |
13 |     match function(string.as_str()) {
   |                    ^^^^^^ does not live long enough
...
18 | }
   | - borrowed value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 11:1...
  --> src/main.rs:11:1
   |
11 | / fn do_stuff_with_function(function: FunctionType) {
12 | |     let string = String::new();
13 | |     match function(string.as_str()) {
14 | |         Ok(_) => {},
...  |
17 | |    
18 | | }
   | |_^

我理解为什么错误会在其他情况下触发:string只有执行do_stuff_with_function才有效,但do_stuff_with_function会返回function& #39; s调用,包括对其输入值的相同生命周期的引用,即string

然而,我对三点感到困惑:

  1. I match函数调用的结果,然后为两个分支返回()。为什么function返回的值的有效期是否无条件地被抛弃?
  2. 如果我将参数function的调用替换为okay(具有相同签名)的直接引用,则无需投诉即可编译。
  3. 错误消息表明(虽然没有完全说明?)必要的生命周期已经与实际生命周期相同。

1 个答案:

答案 0 :(得分:2)

TL; DR:使用the for<'a> syntax为该函数设置一个特定的生命周期,而不是从使用它的上下文中取一个。

do_stuff_with_function的生命时间缩短隐藏了这里发生的事情。你的实际生命是:

 fn do_stuff_with_function<'a>(function: FunctionType<'a>) {

在函数参数中声明的这个生命周期并不意味着“我将在稍后提出一些随机的短暂生命周期”,而是“在调用此函数时已经存在的生命周期”。

这些生命周期注释不是通配符,而是更像是标识符来跟踪值来自何处以及它们将去往何处。例如,可以使用它们来澄清这样的情况:

fn do_stuff_with_function<'a>(function: FunctionType<'a>, t: &'a str) {
    match function(t) {
        Ok(_) => {},
        Err(_) => {},
    }
}

fn main() {
    let string = String::new();
    do_stuff_with_function(okay, string.as_str());    
}

但是,Rust中的问题是可以解决的,但只需要更高级的语法。出于解释的目的,首先,让我们将其更改为:

fn do_stuff_with_function<'a, F>(function: F) where F: Fn(&'a str) -> Result<(), &'a str> {

这意味着“为每个唯一的do_stuff_with_function制作F的副本,这些&'a str可以是看起来像do_stuff_with_function<'a>(等等)的函数的任何内容。 这与您的代码基本相同(+允许闭包)。但是,我仍然必须将生命周期命名为fn do_stuff_with_function<F>(function: F) where F: for<'a> Fn(&'a str) -> Result<(), &'a str> { 的调用。

所以这是一个freaky type magic

do_stuff_with_function

允许使用Fn语法将生命周期的定义从for<'a>移动到F的定义。这种方式特定于do_stuff_with_function,而不是@RunWith(SpringRunner.class) @RestClientTest({XyzDaoImpl.class}) @TestPropertySource(locations = "classpath:application-test.properties") public class XyzDaoTest { @Autowired XyzDaoImpl xyzDaoImpl; @Test public void testGetXyzDetails(){ assertThat(xyzDaoImpl.getXyzDetails("123", null)).isNotNull(); } } 参数。