Rust 在结构中定义多个生命周期何时有用?

Rust 在结构中定义多个生命周期何时有用?,rust,lifetime,Rust,Lifetime,在Rust中,当我们希望结构包含引用时,通常会将其生命期定义为: struct Foo<'a> { x: &'a i32, y: &'a i32, } struct Foo在熬夜太晚之后,我想出了一个生命周期很重要的例子。代码如下: 静态零点:i32=0; 结构Foo{ x:&'a i32, y:&'b i32, } fn获取x_或zero_ref(x:&'ai32,y:&'bi32)->&'ai32{ 如果*x>*y{ 返回x }否则{ 归零 }

在Rust中,当我们希望结构包含引用时,通常会将其生命期定义为:

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

struct Foo在熬夜太晚之后,我想出了一个生命周期很重要的例子。代码如下:

静态零点:i32=0;
结构Foo{
x:&'a i32,
y:&'b i32,
}
fn获取x_或zero_ref(x:&'ai32,y:&'bi32)->&'ai32{
如果*x>*y{
返回x
}否则{
归零
}
}
fn main(){
设x=1;
让v;
{
设y=2;
设f=Foo{x:&x,y:&y};
v=获取x或零参考(&f.x和&f.y);
}
println!({},*v);
}
如果要将
Foo
的定义更改为:


struct Foo这里是另一个简单的示例,其中struct定义必须使用两个生存期才能按预期操作。它不会将聚合拆分为具有不同生存期的字段,而是将结构嵌套到另一个结构中

struct X<'a>(&'a i32);

struct Y<'a, 'b>(&'a X<'b>);

fn main() {
    let z = 100;
    //taking the inner field out of a temporary
    let z1 = ((Y(&X(&z))).0).0;  
    assert!(*z1 == z);
}
struct X);
fn main(){
设z=100;
//将内部场从临时场中移除
设z1=(Y(&X(&z)).0;
断言!(*z1==z);
}
结构
Y
有两个生存期参数,一个用于其包含的字段
&X
,另一个用于
X
的包含字段
&z

在操作
((Y(&X(&z))).0.0
中,
X(&z)
被创建为临时文件并被借用。它的生存期仅在此操作的范围内,在语句结束时过期。但是由于
X(&z)
的生存期不同于其包含的字段
&z
,因此该操作可以返回
&z
,其值可以稍后在函数中访问

如果对
Y
struct使用单一生存期。此操作将不起作用,因为
&z
的生存期与其包含的结构
X(&z)
相同,在语句末尾过期;因此,返回的
&z
不再有效,以后无法访问


请参阅中的代码。

我想在这里重新回答我的问题,因为它仍然在搜索结果中显示得很高,我觉得我可以更好地解释。考虑这个代码:

这是怎么回事

  • f.x
    的寿命要求至少足够大,以涵盖
    x
    的范围,直到
    println语句(因为它是用
    &x
    初始化的,然后分配给
    v
  • Foo
    的定义规定
    f.x
    f.y
    使用相同的通用生存期
    'a
    ,因此
    f.y
    的生存期必须至少与
    f.x
    一样大
  • 但是,这不起作用,因为我们将
    &y
    分配给
    f.y
    ,并且
    y
    println之前超出范围。错误
    这里的解决方案是允许
    Foo
    f.x
    f.y
    使用单独的生存期,我们使用多个通用生存期参数:

    structfoo{
    x:&'a i32,
    y:&'b i32,
    }
    

    现在,
    f.x
    f.y
    的生命周期没有联系在一起。编译器仍将使用有效的生存期,直到
    println用于
    f.x
    的语句。但是不再要求
    f.y
    使用相同的生存期,因此编译器可以自由地为
    f.y
    选择较小的生存期,例如仅对
    y
    范围有效的生存期!我写了差不多相同的东西,15分钟前停电了。我正要把它寄出去。是的,我能想到的唯一一种情况是,当您希望能够获取一个聚合值并在使用它之后分割它的一部分,而不会丢失生存期信息。考虑建立一组值(可能涉及生命周期),使用它,然后恢复原始值。当然可以省略get_x_或_zero_ref中的'b',因为它是默认生命周期省略规则所隐含的。说函数“需要”其参数具有不同的生命周期是没有意义的。生命周期参数的用途是防止函数或结构将这些参数统一到单个(推断的)生命周期中,因此借用检查器可以区分它们。如果表达式
    X(&z)
    提升到其自身变量中,则可以删除Y的额外生命周期。i、 e.
    设x=x(&z)
    。是否有另一种方法强制需要额外的寿命参数?我目前正在试图理解为什么函数可能需要大于1个生存期参数。@StevenShaw是的。单独的变量x将把x(&z)提升到与z相同的作用域级别,而不是z的构造函数中的临时变量。另一方面,我的回答中的情况不是一个概念游戏,而是发生在我的实际项目中。我只是把它简化成给定的代码。对于函数,更常见的是有多个生存期参数。例如,您有两个输入借用,但返回值的生存期仅依赖于其中一个输入的生存期。谢谢,我想这可能是因为我只能在更广泛的上下文中看到它。我已经尽力想出了一个小例子,它要求函数上有多个生存期参数。例如,接受的答案可以简单地删除函数的第二个参数。如果在
    main
    中删除不必要的作用域,它甚至可以删除结构的第二个参数。我已经收起了你的漂亮短语“概念游戏”,并将你的书添加到我的愿望列表中。@StevenShaw能够删除第二个输入的生存期参数(同时保留第一个)已经意味着它们有两个不同的生存期参数。只是根据“终身省略”规则,一个人被省略了。其次,t中
    main()
    v
    的内部范围
    struct X<'a>(&'a i32);
    
    struct Y<'a, 'b>(&'a X<'b>);
    
    fn main() {
        let z = 100;
        //taking the inner field out of a temporary
        let z1 = ((Y(&X(&z))).0).0;  
        assert!(*z1 == z);
    }
    
    struct Foo<'a> {
        x: &'a i32,
        y: &'a i32,
    }
    
    fn main() {
        let x = 1;
        let v;
        {
            let y = 2;
            let f = Foo { x: &x, y: &y };
            v = f.x;
        }
        println!("{}", *v);
    }
    
    error[E0597]: `y` does not live long enough
    --> src/main.rs:11:33
    |
    11 |         let f = Foo { x: &x, y: &y };
    |                                 ^^ borrowed value does not live long enough
    12 |         v = f.x;
    13 |     }
    |     - `y` dropped here while still borrowed
    14 |     println!("{}", *v);
    |                    -- borrow later used here
    
    struct Foo<'a, 'b> {
        x: &'a i32,
        y: &'b i32,
    }