gpt4 book ai didi

rust - 关于理解生命周期的问题

转载 作者:行者123 更新时间:2023-12-04 16:36:58 24 4
gpt4 key购买 nike

我一直很难理解生命周期,如果能帮助我理解这里的资源和其他问题/答案中通常缺少的一些微妙之处,我将不胜感激。甚至本书的整个部分都具有误导性,因为它的主要示例被用作生命周期背后的基本原理或多或少是错误的(即编译器可以很容易地推断出所提到函数的生命周期)。


以这个函数(有点像书上的)为例:

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

我的理解是显式生命周期断言返回引用的生命周期不应长于xy 的最短生命周期。或者换句话说,xy 都应该比返回的引用长寿。 (虽然我完全不确定编译器到底做了什么,但它会检查参数的生命周期,然后将最小值与返回引用的生命周期进行比较吗?)

但是如果我们没有返回值,那么生命周期意味着什么呢?它是否意味着特殊的含义(例如,与使用两个不同的生命周期相比?)

fn foo<'a>(x: &'a str, y: &'a str) {

}

然后我们有如下结构:

struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}

struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}

似乎对字段使用相同的生命周期会增加一些约束,但导致 some examples 的约束到底是什么?不上类?


这可能需要一个自己的问题,但是有很多生命周期和范围的不同提及但没有详细说明,是否有任何资源对此进行更深入的研究,尤其是考虑非词汇生命周期?

最佳答案

要了解生命周期,您必须注意它们实际上是类型的一部分,而不是值的一部分。这就是将它们指定为通用参数的原因。

也就是说,当你写:

fn test(a: &i32) {
let i: i32 = 0;
let b: &i32 = &i;
let c: &'static i32 = &0;
}

然后是变量 a , bc实际上是不同的类型:一种是&'__unnamed_1 i32 , 另一个是 &_unnamed_2 i32另一个是&'static i32 .

有趣的是,生命周期创建了一个类型层次结构,因此当一种类型比另一种类型生命周期更长,但除了它们相同之外,那么长生命周期类型是短生命周期类型的子类型.

特别是,在极端多重继承的情况下,&'static i32 type 是任何其他 &'_ i32 的子类型.

您可以使用此示例检查 Rust 子类型是否真实:

fn test(mut a: &i32) {
let i: i32 = 0;
let mut b: &i32 = &i;
let mut c: &'static i32 = &0;
//c is a subtype of a and b
//a is a subtype of b
a = c; // ok
c = a; // error
b = a; // ok
a = b; // error
}

值得注意的是,生命周期是一个借用检查器的问题。一旦满足并且代码被证明是安全的,生命周期将被删除并且代码生成是盲目完成的,假设所有对内存值的访问都是有效的。这就是为什么即使生命周期是通用参数,foo<'a>()仅实例化一次。

回到你的例子:

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

你可以用不同生命周期的值调用这个函数,因为编译器会推导出'a作为两者中较短的一个,所以 &'a str将是另一个的父类(super class)型:

    let s = String::from("hello");
let r = foo(&s, "world");

这等同于(为生命周期注释发明的语法):

    let s: &'s str = String::from("hello");
let r: &'s str = foo::<'s>(&s, "world" as &'s str);

关于具有多个生命周期的结构,这通常无关紧要,我通常将所有生命周期声明为相同,特别是如果该类型对我的 crate 是私有(private)的。

但对于公共(public)泛型类型,声明多个生命周期可能很有用,特别是因为用户可能希望制作一些生命周期'static .

例如:

struct Foo<'a, 'b> {
x: &'a i32,
y: &'b str,
}

struct Bar<'a> {
x: &'a i32,
y: &'a str,
}

Foo 的用户可以将其用作:

let x = 42;
let foo = Foo { x: &x, y: "hello" };

但是Bar的用户必须分配一个 String ,或者做一些堆栈分配的 str魔法:

let x = 42;
let y = String::from("hello");
let bar = Bar { x: &x, y: &y };

请注意 Foo可以像Bar一样使用但反之则不然。

还有 impl Foo可能会提供 impl Bar 无法提供的附加功能:

impl<'a> Foo<'a, 'static> {
fn get_static_str(&self) -> &'static str {
self.y
}
}

关于rust - 关于理解生命周期的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68763457/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com