gpt4 book ai didi

rust - 在 Rust 中将生命周期与结构一起使用的正确方法是什么?

转载 作者:行者123 更新时间:2023-11-29 07:40:58 25 4
gpt4 key购买 nike

我想写这个结构:

struct A {
b: B,
c: C,
}

struct B {
c: &C,
}

struct C;

B.c应该是从A.c中借用的

A ->
b: B ->
c: &C -- borrow from --+
|
c: C <------------------+

这是我尝试过的: 结构 C;

struct B<'b> {
c: &'b C,
}

struct A<'a> {
b: B<'a>,
c: C,
}

impl<'a> A<'a> {
fn new<'b>() -> A<'b> {
let c = C;
A {
c: c,
b: B { c: &c },
}
}
}

fn main() {}

但失败了:

error[E0597]: `c` does not live long enough
--> src/main.rs:17:24
|
17 | b: B { c: &c },
| ^ borrowed value does not live long enough
18 | }
19 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'b as defined on the method body at 13:5...
--> src/main.rs:13:5
|
13 | fn new<'b>() -> A<'b> {
| ^^^^^^^^^^^^^^^^^^^^^

error[E0382]: use of moved value: `c`
--> src/main.rs:17:24
|
16 | c: c,
| - value moved here
17 | b: B { c: &c },
| ^ value used here after move
|
= note: move occurs because `c` has type `C`, which does not implement the `Copy` trait

我已经阅读了关于所有权的 Rust 文档,但我仍然不知道如何修复它。

最佳答案

实际上,上述代码失败的原因不止一个。让我们对其进行一些分解,并探讨一些修复方法。

首先让我们删除 new 并尝试直接在 main 中构建 A 的实例,以便您看到问题与生命周期无关:

struct C;

struct B<'b> {
c: &'b C,
}

struct A<'a> {
b: B<'a>,
c: C,
}

fn main() {
// I copied your new directly here
// and renamed c1 so we know what "c"
// the errors refer to
let c1 = C;

let _ = A {
c: c1,
b: B { c: &c1 },
};
}

这失败了:

error[E0382]: use of moved value: `c1`
--> src/main.rs:20:20
|
19 | c: c1,
| -- value moved here
20 | b: B { c: &c1 },
| ^^ value used here after move
|
= note: move occurs because `c1` has type `C`, which does not implement the `Copy` trait

它说的是,如果您将 c1 分配给 c,您会将其所有权移至 c(即您无法访问它不再通过 c1,只能通过 c)。这意味着对 c1 的所有引用都将不再有效。但是你有一个 &c1 仍在范围内(在 B 中),所以编译器不能让你编译这段代码。

当编译器提示类型 C 不可复制时,它会在错误消息中提示可能的解决方案。如果您可以复制 C,那么您的代码将是有效的,因为将 c1 分配给 c 会创建一个新的副本值而不是移动原始副本的所有权。

我们可以通过像这样更改其定义来使 C 可复制:

#[derive(Copy, Clone)]
struct C;

现在上面的代码可以工作了。注意什么@matthieu-m comments仍然正确:we can't store both the reference to a value and the value itself in B (我们在此处存储对值的引用和该值的 COPY)。不过,这不仅适用于结构,也是所有权的运作方式。

现在,如果您不想(或不能)使 C 可复制,您可以将引用存储在 AB 代替。

struct C;

struct B<'b> {
c: &'b C,
}

struct A<'a> {
b: B<'a>,
c: &'a C, // now this is a reference too
}

fn main() {
let c1 = C;
let _ = A {
c: &c1,
b: B { c: &c1 },
};
}

那还好吗?不是真的...我们仍然想将 A 的创建移回到 new 方法中。这就是我们将在一生中遇到麻烦的地方。让我们将 A 的创建移回到一个方法中:

impl<'a> A<'a> {
fn new() -> A<'a> {
let c1 = C;
A {
c: &c1,
b: B { c: &c1 },
}
}
}

如预期的那样,这是我们的生命周期错误:

error[E0597]: `c1` does not live long enough
--> src/main.rs:17:17
|
17 | c: &c1,
| ^^ borrowed value does not live long enough
...
20 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 13:1...
--> src/main.rs:13:1
|
13 | impl<'a> A<'a> {
| ^^^^^^^^^^^^^^

error[E0597]: `c1` does not live long enough
--> src/main.rs:18:24
|
18 | b: B { c: &c1 },
| ^^ borrowed value does not live long enough
19 | }
20 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 13:1...
--> src/main.rs:13:1
|
13 | impl<'a> A<'a> {
| ^^^^^^^^^^^^^^

这是因为 c1new 方法的末尾被销毁,所以我们不能返回对它的引用。

fn new() -> A<'a> {
let c1 = C; // we create c1 here
A {
c: &c1, // ...take a reference to it
b: B { c: &c1 }, // ...and another
}
} // and destroy c1 here (so we can't return A with a reference to c1)

一个可能的解决方案是在 new 之外创建 C 并将其作为参数传入:

struct C;

struct B<'b> {
c: &'b C,
}

struct A<'a> {
b: B<'a>,
c: &'a C
}

fn main() {
let c1 = C;
let _ = A::new(&c1);
}

impl<'a> A<'a> {
fn new(c: &'a C) -> A<'a> {
A {c: c, b: B{c: c}}
}
}

playground

关于rust - 在 Rust 中将生命周期与结构一起使用的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27589054/

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