为单个变量分配不同的生命周期

Kas*_*ard 6 lifetime rust

仍在尝试了解 Rust 所有权和生命周期,并且我对这段代码感到困惑:

struct Foo {
    x: String,
}

fn get_x<'a, 'b>(a: &'a Foo, b: &'b Foo) -> &'b str {
    let mut bar = &a.x;
    bar = &b.x;
    bar
}
Run Code Online (Sandbox Code Playgroud)

操场

该代码无法编译,因为data from 'a' is returned. 我认为这是因为当我初始化时bar,我分配了一个&'a对它的引用,所以 Rust 假设它bar有生命周期'a。因此,当我尝试返回 type 的值时,&'a str它会抱怨它与返回类型不匹配'b str

我不明白的是:为什么我首先可以分配 a&'b str到?bar如果 Rust 假设bar具有生命周期'a,那么它不应该阻止我分配b.x给它吗?

Fra*_*gné 5

每次借用都有不同的生命周期。Rust 编译器总是试图最小化生命周期,因为较短的生命周期与其他生命周期相交的机会较小,这对于可变借用尤其重要(请记住,任何时候都只能有一个特定内存位置的活动可变借用)。从另一个借用派生的借用生命周期可以短于或等于另一个借用的生命周期,但永远不能更大。

\n

让我们检查一下函数的一个没有任何错误的变体:

\n
fn get_x<'a, 'b>(a: &'a Foo, b: &'b Foo) -> &'b str {\n    let mut bar = &a.x;\n    bar = &b.x;\n    todo!()\n}\n
Run Code Online (Sandbox Code Playgroud)\n

表达式&a.x&b.x创建新的借用引用。这些引用有自己的生命周期;我们称它们为'ax'bx'ax借用自a,其类型为&'a Foo,因此与和一样,'a其生存期也必须比'ax( 'a: 'ax) \xe2\x80\x93长。至今为止,并无关联。'bx'b'ax'bx

\n

为了确定 的类型bar,编译器必须统一'ax'bx。鉴于'ax'bx不相关,我们必须定义一个新的生命周期 ,作为和 的'abx并集,并将该生命周期用于两个借用(替换/精炼和)和 的类型。这个新的生命周期需要承受和 的约束:我们现在有了和。具有生命周期的借用不会从函数中逃逸,并且生命周期和生命周期由于是函数上的生命周期参数而比调用框架更长寿,因此满足约束。'ax'bx'ax'bxbar'ax'bx'a: 'abx'b: 'abx'abx'a'b

\n

现在让我们回到原来的函数:

\n
fn get_x<'a, 'b>(a: &'a Foo, b: &'b Foo) -> &'b str {\n    let mut bar = &a.x;\n    bar = &b.x;\n    bar\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在这里,我们有一个额外的约束: 的类型bar必须与 兼容&'b str。为此,我们必须统一'abx'b。鉴于我们已经做到了'b: 'abx,这种统一的结果很简单'b。然而,我们也有约束'a: 'abx,所以我们应该把这个约束转移到'b,给予'a: 'b

\n

这里的问题是约束'a: 'b仅涉及生命周期参数(而不是匿名生命周期)。生命周期约束构成函数契约的一部分;添加一个是一项 API 重大更改。编译器可以根据函数签名中使用的类型推断出一些生命周期约束,但它永远不会推断仅由函数实现产生的约束(否则实现更改可能会默默地导致 API 破坏性更改)。显式添加where 'a: 'b到函数签名可以使错误消失(尽管它使函数更具限制性,即一些在没有约束的情况下有效的调用在有约束的情况下变得无效):

\n
fn get_x<'a, 'b>(a: &'a Foo, b: &'b Foo) -> &'b str\nwhere\n    'a: 'b,\n{\n    let mut bar = &a.x;\n    bar = &b.x;\n    bar\n}\n
Run Code Online (Sandbox Code Playgroud)\n