我想写这个结构:
struct A {
b: B,
c: C,
}
struct B {
c: &C,
}
struct C;
Run Code Online (Sandbox Code Playgroud)
本B.c
应借A.c
.
A ->
b: B ->
c: &C -- borrow from --+
|
c: C <------------------+
Run Code Online (Sandbox Code Playgroud)
这是我尝试过的:struct 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() {}
Run Code Online (Sandbox Code Playgroud)
但它失败了:
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
Run Code Online (Sandbox Code Playgroud)
我已阅读有关所有权的Rust文档,但我仍然不知道如何修复它.
Pao*_*lla 37
实际上,上述代码失败的原因不止一个.让我们分解一下,探索一些如何解决它的选项.
首先让我们删除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 },
};
}
Run Code Online (Sandbox Code Playgroud)
这失败了:
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
Run Code Online (Sandbox Code Playgroud)
它说的是,如果分配c1
到c
,您将其所有权c
(即你不能再通过访问它c1
,只能通过c
).这意味着所有引用c1
将不再有效.但是你&c1
仍然在范围内(在B中),所以编译器不能让你编译这段代码.
当编译器声明该类型C
是不可复制的时,编译器会在错误消息中提示可能的解决方案.如果你可以做的副本C
,你的代码将被有效,因为分配c1
到c
会创造价值,而不是移动的原件所有权的新副本.
我们可以C
通过改变它的定义来复制:
#[derive(Copy, Clone)]
struct C;
Run Code Online (Sandbox Code Playgroud)
现在上面的代码工作了.请注意,@ matthieu-m注释仍然是正确的:我们不能同时存储对值的引用和值本身(我们在这里存储对值的引用和值的COPY).不仅仅是结构,这是所有权的运作方式.
现在,如果您不想(或不能)制作可C
复制的,您可以在两者中存储引用,A
而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 },
};
}
Run Code Online (Sandbox Code Playgroud)
一切都好吗?不是......我们仍然希望将创建A
重新转移到new
方法中.而这就是我们将终生遇到麻烦的地方.让我们将创建A
重新转移到一个方法中:
impl<'a> A<'a> {
fn new() -> A<'a> {
let c1 = C;
A {
c: &c1,
b: B { c: &c1 },
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,这是我们的终身错误:
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> {
| ^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
这是因为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)
Run Code Online (Sandbox Code Playgroud)
一种可能的解决方案是在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}}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
16097 次 |
最近记录: |