为什么生存期名称会出现在函数类型中? [英] Why does the lifetime name appear as part of the function type?

查看:91
本文介绍了为什么生存期名称会出现在函数类型中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我相信此函数声明告诉Rust函数输出的生存期与它的s参数的生存期相同:

I believe that this function declaration tells Rust that the lifetime of the function's output is the same as the lifetime of it's s parameter:

fn substr<'a>(s: &'a str, until: u32) -> &'a str;
         ^^^^

在我看来,编译器只需要知道this(1):

It seems to me that the compiler only needs to know this(1):

fn substr(s: &'a str, until: u32) -> &'a str;

函数名称后的注释<'a>是什么意思?为什么编译器需要它,它有什么用?

What does the annotation <'a> after the function name mean? Why does the compiler need it, and what does it do with it?

(1):由于终身淘汰,我知道它需要知道的甚至更少.但是这个问题是关于明确指定生存期的.

(1): I know it needs to know even less, due to lifetime elision. But this question is about specifying lifetime explicitly.

推荐答案

让我扩展先前的答案...

Let me expand on the previous answers…

函数名称后的注释<'a>是什么意思?

What does the annotation <'a> after the function name mean?

我不会为此使用注释"一词.与<T>引入通用的 type 参数一样,<'a>引入通用的 lifetime 参数.您必须先引入通用参数,然后才能使用任何通用参数;对于通用函数,此介绍恰好在其名称之后进行.您可以将泛型函数视为函数族.因此,从本质上讲,每种通用参数组合都会得到一个函数. substr::<'x>在整个生命周期'x内将是该功能家族的特定成员.

I wouldn't use the word "annotation" for that. Much like <T> introduces a generic type parameter, <'a> introduces a generic lifetime parameter. You can't use any generic parameters without introducing them first and for generic functions this introduction happens right after their name. You can think of a generic function as a family of functions. So, essentially, you get one function for every combination of generic parameters. substr::<'x> would be a specific member of that function family for some lifetime 'x.

如果您不清楚我们何时以及为什么必须明确说明生命周期,请继续阅读...

If you're unclear on when and why we have to be explicit about lifetimes, read on…

生命周期参数始终与所有引用类型相关联.当你写

A lifetime parameter is always associated with all reference types. When you write

fn main() {
    let x = 28374;
    let r = &x;
}

编译器知道x存在于用花括号括起来的主函数范围内.在内部,它使用一些生命周期参数来标识此范围.对于我们来说,它是未命名的.当您使用地址x时,将获得特定引用类型的值.引用类型是二维引用类型族的成员.一个轴是参考指向的类型,另一个轴是用于两个约束的寿命:

the compiler knows that x lives in the main function's scope enclosed with curly braces. Internally, it identifies this scope with some lifetime parameter. For us, it is unnamed. When you take the address of x, you'll get a value of a specific reference type. A reference type is kind of a member of a two dimensional family of reference types. One axis is the type of what the reference points to and the other axis is a lifetime that is used for two constraints:

  1. 引用类型的生命周期参数表示您可以保留该引用多长时间的上限
  2. 引用类型的生命周期参数表示您可以将引用指向的事物的生命周期的下限.

这些约束一起在Rust的内存安全故事中起着至关重要的作用.此处的目的是避免悬挂参考.我们想排除指向不再允许使用的某些内存区域的引用,因为它所指向的内容不再存在.

Together, these constraints play a vital role in Rust's memory safety story. The goal here is to avoid dangling references. We would like to rule out references that point to some memory region we are not allowed to use anymore because that thing it used to point to does not exist anymore.

一个潜在的混乱根源可能是这样一个事实,即寿命参数在大多数情况下是不可见的.但这并不意味着它们不存在.引用总是在其类型中具有生命周期参数.但是,这样的生命周期参数不必具有名称,并且在大多数情况下我们都无需提及它,因为编译器可以自动为生命周期参数分配名称.这称为终身淘汰".例如,在以下情况下,您不会看到提及任何生命周期参数:

One potential source of confusion is probably the fact that lifetime parameters are invisible most of the time. But that does not mean they are not there. References always have a lifetime parameter in their type. But such a lifetime parameter does not have to have a name and most of the time we don't need to mention it anyways because the compiler can assign names for lifetime parameters automatically. This is called "lifetime elision". For example, in the following case, you don't see any lifetime parameters being mentioned:

fn substr(s: &str, until: u32) -> &str {…}

但是可以这样写.实际上,这是更明确的捷径

But it's okay to write it like this. It's actually a short-cut syntax for the more explicit

fn substr<'a>(s: &'a str, until: u32) -> &'a str {…}

在这里,编译器会自动为输入生存期"和输出生存期"分配相同的名称,因为这是一种非常常见的模式,并且很可能正是您想要的.由于这种模式非常普遍,因此编译器使我们无需考虑生命周期就可以脱身. 假设,这种更明确的形式是我们基于几个终身淘汰"规则(至少在

Here, the compiler automatically assigns the same name to the "input lifetime" and the "output lifetime" because it's a very common pattern and most likely exactly what you want. Because this pattern is so common, the compiler lets us get away without saying anything about lifetimes. It assumes that this more explicit form is what we meant based on a couple of "lifetime elision" rules (which are at least documented here)

在某些情况下,显式生存期参数不是可选.例如,如果您写

There are situations in which explicit lifetime parameters are not optional. For example, if you write

fn min<T: Ord>(x: &T, y: &T) -> &T {
    if x <= y {
        x
    } else {
        y
    }
}

编译器会抱怨,因为它将上述声明解释为

the compiler will complain because it will interpret the above declaration as

fn min<'a, 'b, 'c, T: Ord>(x: &'a T, y: &'b T) -> &'c T { … }

因此,对于每个参考,都会引入一个单独的生存期参数.但是在此签名中没有有关寿命参数如何相互关联的信息.此泛型函数的用户可以使用 any 生存期.这就是它体内的问题.我们试图返回xy.但是x的类型是&'a T.这与返回类型&'c T不兼容. y也是如此.由于编译器对这些生存期之间的关系一无所知,因此将这些引用作为类型&'c T的引用返回是不安全的.

So, for each reference a separate lifetime parameter is introduced. But no information on how the lifetime parameters relate to each other is available in this signature. The user of this generic function could use any lifetimes. And that's a problem inside its body. We're trying to return either x or y. But the type of x is &'a T. That's not compatible with the return type &'c T. The same is true for y. Since the compiler knows nothing about how these lifetimes relate to each other, it's not safe to return these references as a reference of type &'c T.

从类型&'a T&'c T的值是否安全?是的.如果寿命'a等于寿命或大于寿命'c,则是安全的.或者换句话说'a: 'c.所以,我们可以写这个

Can it ever be safe to go from a value of type &'a T to &'c T? Yes. It's safe if the lifetime 'a is equal or greater than the lifetime 'c. Or in other words 'a: 'c. So, we could write this

fn min<'a, 'b, 'c, T: Ord>(x: &'a T, y: &'b T) -> &'c T
      where 'a: 'c, 'b: 'c
{ … }

,不用编译器就可以抱怨函数的主体了​​.但这实际上是不必要的,很复杂.我们也可以简单地写

and get away with it without the compiler complaining about the function's body. But it's actually unnecessarily complex. We can also simply write

fn min<'a, T: Ord>(x: &'a T, y: &'a T) -> &'a T { … }

,并对所有内容使用单个生命周期参数.编译器能够推断出'a作为调用站点上参数引用的最小生存期,仅因为我们对两个参数使用了相同的生存期名称.而这正是我们返回类型所需要的寿命.

and use a single lifetime parameter for everything. The compiler is able to deduce 'a as the minimum lifetime of the argument references at the call site just because we used the same lifetime name for both parameters. And this lifetime is precisely what we need for the return type.

我希望这能回答您的问题. :) 干杯!

I hope this answers your question. :) Cheers!

这篇关于为什么生存期名称会出现在函数类型中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆