值“不够长”,但仅在使用函数指针时

问题描述 投票:1回答:1

我正在尝试使用以下简化代码进行编译:

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调用的值,该调用包括对其输入值的相同生命周期的引用,即string

但是,我对三点感到困惑:

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

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


do_stuff_with_function的args上终身省略隐藏了这里发生的事情。你的实际生命是:

 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>的呼唤联系在一起。

所以这是一个freaky type magic

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

这允许使用do_stuff_with_function语法将生命周期的定义从Fn移动到for<'a>的定义。这种方式特定于F,而不是do_stuff_with_function论点。

© www.soinside.com 2019 - 2024. All rights reserved.