为什么对通用功能不需要生命

发布于 2025-01-18 16:16:36 字数 1301 浏览 0 评论 0原文

此代码不会编译,因为Rust需要添加一生。

fn firstNoLifetime(x: &str, y: &str) -> &str {
    return x;
}

因此,相反,我们必须明确地添加终身:

fn first<'a>(x: &'a str, y: &'a str) -> &'a str {
    return x;
}

我的问题是,该功能在没有终生的情况下如何编译?
为什么通用功能不需要生命,并且周围是否有任何警告?

fn first_generic<A>(x: A, y: A) -> A {
    return x;
}

我的假设是,终生注释有助于编译器并借用检查器确定终身违规行为的根本原因,但是在下面的代码中,Rust能够确定原因而没有注释。我的假设错误吗?如果是这样,终生注释的目的是什么?

fn first_generic<A>(x: A, y: A) -> A {
    return x;
}

fn main() {
    let string1 = String::from("long string is long");
    let result: &str;
    {
        let string2 = String::from("xyz");
        result = first_generic(string1.as_str(), string2.as_str());
    }

    println!("The first string is: {}", result);
}

结果:

   |
10 |         result = first_generic(string1.as_str(), string2.as_str());
   |                                                  ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
11 |     }
   |     - `string2` dropped here while still borrowed
12 | 
13 |     println!("The first string is: {}", result);
   |                                           ------ borrow later used here

This code won't compile because rust requires a lifetime to be added.

fn firstNoLifetime(x: &str, y: &str) -> &str {
    return x;
}

So instead we must add the lifetime explicitly like this:

fn first<'a>(x: &'a str, y: &'a str) -> &'a str {
    return x;
}

My question then is, how is it, that this function, without lifetimes, compiles ?
Why are lifetimes not required for generic functions, and are there any caveats around that ?

fn first_generic<A>(x: A, y: A) -> A {
    return x;
}

My assumption was that lifetime annotations help the compiler and borrow checker determine the root cause of lifetime violations, but in the code below rust was able to determine the cause without annotations. Is my assumption wrong ? And if so, what is the purpose of lifetime annotations ?

fn first_generic<A>(x: A, y: A) -> A {
    return x;
}

fn main() {
    let string1 = String::from("long string is long");
    let result: &str;
    {
        let string2 = String::from("xyz");
        result = first_generic(string1.as_str(), string2.as_str());
    }

    println!("The first string is: {}", result);
}

result:

   |
10 |         result = first_generic(string1.as_str(), string2.as_str());
   |                                                  ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
11 |     }
   |     - `string2` dropped here while still borrowed
12 | 
13 |     println!("The first string is: {}", result);
   |                                           ------ borrow later used here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

深陷 2025-01-25 16:16:36

当函数签名中省略生命周期时,每个输入生命周期将成为不同的匿名生命周期参数。因此,这:

fn firstNoLifetime(x: &str, y: &str) -> &str {
    return x;
}

等同于:

fn firstNoLifetime<'a, 'b>(x: &'a str, y: &'b str) -> &'? str {
    return x;
}

返回值的生命周期是多少?在这里使用不同的生命周期是没有意义的,因为没有有用的引用可以满足该生命周期。

根据终身省略规则,当存在单个 输入生命周期,然后该生命周期用于返回值。如果有多个输入生命周期,但其中之一是 &self&mut self,则 self 的生命周期为用于返回值。这些规则的原因是我们不希望生命周期推断基于函数的实现,因为实现的更改可能会导致签名更改,这通常是一个重大更改。

泛型函数起作用的原因是生命周期参数是引用类型的一部分。当您使用引用调用 first_generic 时,编译器必须找到一个与两个参数兼容的单一类型(包括找到共同的生命周期),就像它的方式一样首先是。我们在 firstNoLifetime 中遇到的错误不会在 first_generic 中发生,因为 firstNoLifetime 的参数具有不同的类型,而在 first_generic 中不会发生这种情况code> 因为我们指定两个参数具有相同的类型 A(无论 A 是什么)。

When lifetimes are elided in a function signature, each input lifetime becomes a distinct anonymous lifetime parameter. Thus, this:

fn firstNoLifetime(x: &str, y: &str) -> &str {
    return x;
}

is equivalent to this:

fn firstNoLifetime<'a, 'b>(x: &'a str, y: &'b str) -> &'? str {
    return x;
}

What's the lifetime for the return value, though? It doesn't make sense to use a distinct lifetime here, since no useful reference could satisfy that lifetime.

Per lifetime elision rules, when there's a single input lifetime, then that lifetime is used for the return value. If there is more than one input lifetime, but one of them is &self or &mut self, then the lifetime of self is used for the return value. The reason for these rules is that we don't want lifetime inference to be based on a function's implementation, because then a change in the implementation could lead to the signature changing, which will generally be a breaking change.

The reason the generic function works is because the lifetime parameter is part of the type of a reference. When you invoke first_generic with references, then the compiler has to find a single type that is compatible with both arguments (including finding a common lifetime), the same way it would have to for first. The error we get with firstNoLifetime cannot happen with first_generic because firstNoLifetime's parameters have different types, which cannot happen with first_generic because we specified that the two parameters have the same type A (whatever A is).

苏佲洛 2025-01-25 16:16:36

寿命是类型本身的一部分

,您将相同的IE 'a指定到所有xy和返回值。如果您收到单个值作为参考,则不必通过终身规范符对吗?

fn first(x: &str) -> &str {
    x
}

这是因为编译器本身推断出两者的寿命。

回到您的问题:“为什么在通用功能中不需要生命的时间”,简短的答案是他们做的。只是不是您提供的例子。为什么?

在第二个示例中,您表明Xy和返回值必须具有与所有类型相同的类型,它们都是a。提醒终生是类型本身的一部分,这里只有一个生命的生命,因此编译器可以自行推断出来。

我的假设是终生注释有助于编译器并借用检查器确定终身违规的根本原因,

是的,您的假设也正确。终身注释确实有助于编译器&amp;在这种情况下,借用检查器以确定终身违规的根本原因。

但是在下面的代码中,生锈能够确定原因而没有注释

,如上所述,这里只有一个生命,因此Rust能够自行推断出来。但是,在某些较旧版本的Rust编译器中,情况并非如此(我不记得确切的版本,但是当时,我们也必须在您的通用情况下指定终生注释)

Lifetimes are part of type itself

In your first example, you are specifying same i.e 'a to all of x, y and return value. If you were receiving single value as reference you wont have to pass lifetime specifier right?

fn first(x: &str) -> &str {
    x
}

It's because compiler infer the lifetime of both on it's own.

Back to your question, "why lifetimes are not required in generic function", short answer is yes they do. Just not in example you provided. Why?

In your second example, you are presenting that x, y and return value must have same type as all of they are A. Reminding that lifetime are part of type itself, here comes only one lifetime comes into play, so compiler can infer it on it's own.

My assumption was that lifetime annotations help the compiler and borrow checker determine the root cause of lifetime violations,

Yes your assumption is also correct. Lifetime annotation do help compiler & borrow checker in this case to determine root cause of lifetime violation.

but in the code below rust was able to determine the cause without annotations

As mentioned above, only one lifetime is in play here so rust was able to infer on it's own. However this was not true in certain older version of rust compiler ( I don't remember exact version but at that time, we had to specify lifetime annotation in your generic case too )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文