繁体   English   中英

结构体所有字段的生命周期参数相同

[英]Same lifetime parameter for all fields of a struct

这是代码:

#[derive(Debug)]
struct Foo {
    f: i32,
}

#[derive(Debug)]
struct Bar<'a> {
    bar1: &'a Foo,
    bar2: &'a Foo,
}

#[allow(unused_variables)]
fn make_bar<'a>(foo1: &'a Foo, foo2: &'a Foo) -> Bar<'a> {
    Bar {
        bar1: foo1,
        bar2: foo2,
    }
}

fn extract_bar2<'a>(foo: &'a Foo) -> &'a Foo {
    let foo1 = Foo { f: 22 };
    let foo2 = make_bar(&foo, &foo1).bar1;
    foo2
}

fn main() {
    let foo = Foo { f: 11 };
    let foo1 = extract_bar2(&foo);
    println!("foo1: {:?}", foo1);
}

这给出了一个错误:

error: `foo1` does not live long enough
  --> src/main.rs:23:32
   |>
23 |>     let foo2 = make_bar(&foo, &foo1).bar1;
   |>                                ^^^^
note: reference must be valid for the lifetime 'a as defined on the block at 21:45...
  --> src/main.rs:21:46
   |>
21 |> fn extract_bar2<'a>(foo: &'a Foo) -> &'a Foo {
   |>                                              ^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 22:29
  --> src/main.rs:22:30
   |>
22 |>     let foo1 = Foo { f: 22 };
   |>                              ^

核心问题是:生命周期参数在结构的上下文中实际上意味着什么?

更具体地说:对结构的所有字段使用相同的生命周期参数会产生什么后果? 他们的一生必须完全一样吗? 它们必须重叠吗? 如果是这样,它们应该重叠到什么程度?

以下两个结构之间的(语义和实际)差异是什么?

struct Bar<'b> {
    bar1: &'b Foo,
    bar2: &'b Foo,
}
struct Bar<'a, 'b> {
    bar1: &'a Foo,
    bar2: &'b Foo,
}

以下两个结构之间的(语义和实际)差异是什么?

有一个小例子来说明差异:

#[derive(Debug)]
struct Foo;

#[derive(Debug)]
struct Bar1<'b> {
    foo1: &'b Foo,
    foo2: &'b Foo,
}

#[derive(Debug)]
struct Bar2<'a, 'b> {
    foo1: &'a Foo,
    foo2: &'b Foo,
}

fn main() {//'a -->
    let foo1 = Foo;
    let ref_foo1 = 
    {//'b -->
        let foo2 = Foo;
        //error: `foo2` does not live long enough
        //replace the Bar1 with Bar2 in the row below to fix error 
        let bar = Bar1{foo1:&foo1, foo2:&foo2};
        bar.foo1
    };//--> 'b
    println!("ref_foo1={:?}", ref_foo1);
}//--> 'a

Bar1将其成员的生命周期截断到它们的交集。 因此,您无法从Bar1结构中获得对生命周期为'afoo1的引用。 你得到了生命周期'b的引用。

我应该注意到这种情况下的错误信息有点误导

我将粘贴来自 reddit 的一个我非常满意的答案。

编译器可以通过获取它们的交集来组合生命周期。 也就是说,如果你有'a'b ,则有一个路口, 'c'a'b在此期间,双方寿命是‘活着’。 我相信这个交集总是等于 'a 和 'b 中最短的,因为范围界定的工作方式,但也许我错了。

实际上,这意味着,当您看到fn<'a>(x: &'a T, y: &'a U) -> &'a V ,您可以放入&'static T&'b U ,你会得到 a &'b V ,因为'static'b的交集是'b

那么,为什么您的方法会导致编译器抱怨? 因为对编译器来说它有点像这样(它不是有效的语法):

fn extract_bar2<'a>(foo: &'a Foo) -> &'a Foo {
    'b: {
        let foo1 = Foo { f: 22 };
        'c: { // The next line is wrong
            let foo2: &'a Foo = make_bar<'a>(&'a foo, &'b foo1).bar1;
            'd: {
                return foo2;
            }
        }
    }
}

我已经使范围更加明确。 发生什么了? 编译器知道 foo2 必须具有类型&'a Foo ,因为这是函数返回的内容。 所以 make_bar 返回的 Bar 一定有生命周期'a :否则我们无法从中得到&'a Foo 所以我们必须调用make_bar<'a> 但其中一个论点是错误的! foo2不具有寿命'a ,它具有寿命'b ,这是由活得比'a 如果你走十字路口并这样做:

    let foo2: &'b Foo = make_bar<'b>(&'a foo, &'b foo1).bar1;

那么foo2与返回类型不匹配。

当您使用Bar的第二个定义时,代码将起作用,因为在这种情况下bar1bar2不需要具有相同的生命周期。 所以你的第二个 Bar 定义更灵活,但实际上你很少需要额外的灵活性,额外的生命周期注释很烦人。

归功于https://www.reddit.com/user/thiez

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM