实际上,上面的代码失败的原因不止一个。让我们稍微分解一下,并探讨一些修复方法。
首先我们删除new
并尝试构建一个实例A
直接在main
,这样你就会发现问题的第一部分与生命周期无关:
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
to c
,您将其所有权移至c
(即您无法再通过c1
,仅通过c
)。这意味着所有引用c1
将不再有效。但你有一个&c1
仍在范围内(在 B 中),因此编译器无法让您编译此代码。
当编译器指出该类型时,会在错误消息中提示可能的解决方案C
是不可复制的。如果您可以复印一份C
,那么您的代码将是有效的,因为分配c1
to c
将创建该值的新副本,而不是移动原始副本的所有权。
我们可以做C
可通过更改其定义来复制,如下所示:
#[derive(Copy, Clone)]
struct C;
现在上面的代码可以工作了。注意什么@matthieu-m 评论 https://stackoverflow.com/questions/27589054/what-is-the-correct-way-to-use-lifetimes-with-a-struct-in-rust#comment43603185_27589054仍然是这样:我们不能同时将值的引用和值本身存储在 B 中 https://stackoverflow.com/q/32300132/155423(我们在此处存储对值的引用和该值的副本)。但这不仅仅适用于结构,这也是所有权的运作方式。
现在,如果你不想(或不能)C
可复制,您可以在两者中存储引用A
and B
反而。
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> {
| ^^^^^^^^^^^^^^
这是因为c1
在结束时被摧毁new
方法,因此我们无法返回对其的引用。
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)
一种可能的解决方案是创建C
在外面new
并将其作为参数传递:
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}}
}
}