【问题标题】:What is the meaning of 'a: 'a in generic lifetime parameters?'a:'a 在通用生命周期参数中的含义是什么?
【发布时间】:2021-04-08 15:33:44
【问题描述】:

我有一段奇怪的代码:

#![allow(unused)]

fn f<'a>() {}
fn g<'a: 'a>() {}

fn main() {
    // let pf = f::<'static> as fn(); // (7)
    let pg = g::<'static> as fn();    // (8)
    //print!("{}", pf == pg);
}

第 7 行不加注释无法编译(如下错误),但第 8 行可以编译。

error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
 --> src/main.rs:7:18
  |
7 |     let pf = f::<'static> as fn(); // (7)
  |                  ^^^^^^^
  |
note: the late bound lifetime parameter is introduced here
 --> src/main.rs:3:6
  |
3 | fn f<'a>() {}
  |      ^^

第4行'a: 'a是什么意思?

【问题讨论】:

  • 我能找到的f::&lt;'static&gt; 中错误的唯一引用是in the rusc dev guide。看起来&lt;'a&gt;是一个后期绑定参数,但&lt;'a: 'a&gt;是一个早期绑定参数,明确指定后期绑定参数是非法的。我不确定为什么,但它可能值得在rust-internals 发帖,如果只是因为错误消息非常粗略并且可能有关于如何清理它的想法。
  • 如果在函数参数中实际使用了生命周期,both 会出现错误。这个简化的示例不太可能出现在“真实”代码中。确切的错误消息似乎是与 GAT 工作相关的更改的副作用。
  • 您是否阅读了 dtolnay 网站上的问题描述?特别是“根据这些规则,签名fn f&lt;'a&gt;() 具有后期绑定生命周期参数,而签名fn g&lt;'a: 'a&gt;() 具有早期绑定生命周期参数——即使此处的约束无效。”

标签: rust lifetime


【解决方案1】:

我在 rust 文档中没有发现任何要确认的内容,但似乎 &lt;'a: 'a&gt; 不足以限定函数的输出生命周期(参见文档中的生命周期输出)。

这里有一些测试似乎证实了这一点:

#![allow(unused)]

fn f<'a>() {}
fn g<'a: 'a>() {}
fn h<'a: 'a>() -> &'a i32 { &5 }
fn i<'a>() -> &'a i32 { &6 }

fn tst1<'b>() {
   let w:&'b i32 = &6;
   //let pj = f::<'b> as fn();
   let pk = i::<'b> as fn() -> &'b i32;
}

fn tst2<'b>() {
   let pr = g::<'b> as fn();
}
fn main() {
    //let pf = f::<'static> as fn(); // (7)
    let pg = g::<'static> as fn();    // (8)
    let ph = h::<'static> as fn() -> &'static i32;
    let pi = i::<'static> as fn() -> &'static i32;

    //print!("{}", pf == pg);
}

使用 Rustc 1.41.1 编译。最近的更新可能会对此产生影响。

如您所见,let pilet pk 编译为 fn i&lt;'a&gt;(),但不是 let pflet pj 编译为 fn f&lt;'a&gt;()fn i&lt;'a&gt;() 仅与 fn f&lt;'a&gt;() 不同,因为前者返回一个值,因此意味着函数的输出提升时间。

tst1tst2 使用函数的内部生命周期验证这一点。

如果没有文档参考,就无法 100% 确定,但似乎如果您不为函数指定输出,对于函数的指针,您仍然有一个定义的输出生命周期,&lt;'a: 'a&gt; 似乎暗示那个。

关于多亏了@Konstantin W 的 dtolnay 测验,似乎函数的输出生命周期变成早于&lt;'a: 'a&gt; 并且编译器不会因此而尖叫在指针分配时分配'static 生命周期时的情况。

如果是这样,let pilet pk 编译为 fn i&lt;'a&gt;() 可能 因为i 函数在输入(如输出)中完全定义,所以生命周期分配可以在指针分配时完成(或者指定的输出意味着输入和输出时间线的早期边界,但我很难相信时间)。也许还有一个未记录的生锈寿命省略规则。

【讨论】:

    【解决方案2】:

    'a 中的 a 只是一个名称。如果你愿意,你可以称它为'mylifetime'golden_eternal_braid。该位置的任何生命周期参数的含义只是声明它。 'static 以外的生命周期未全局定义,因此您不能将函数声明为

    fn f(param: &'a SomeType) {} // error
    

    ...但是如果你声明它,你可以:

    fn f<'a>(param: &'a SomeType) {} // ok
    

    当然,您也可以将生命周期留给推断,将函数声明为

    fn f(param: &SomeType) {}
    

    【讨论】:

    • 我不明白这如何回答g&lt;'a: 'a&gt; 的含义。
    • 一般情况下,&lt;'a: 'b&gt; 表示定义生命周期'a 受生命周期'b 约束。在这种情况下,它只受到自身的约束,因此毫无意义。
    • 那为什么要编译问题中的代码呢?所以不是没有意义,而是有意义的。
    • 正如所写,booth fg 的生命周期是没有意义的,但是 g 上使用的约束将其绑定到足以欺骗有用的编译器。可以通过删除生命周期规范来修复第 7 行,例如 let pf = f as fn();
    猜你喜欢
    • 2015-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 1970-01-01
    • 2021-02-20
    • 1970-01-01
    相关资源
    最近更新 更多