Rust 对生锈的结构使用寿命的正确方法是什么?
我想写这个结构:Rust 对生锈的结构使用寿命的正确方法是什么?,rust,lifetime,Rust,Lifetime,我想写这个结构: struct A { b: B, c: C, } struct B { c: &C, } struct C; B.c应该从A.c借用 A-> b:b-> c:&c--从中借用--+ | c:c, c:c, } 恳求{ fn新{ 设c=c; A{ c:c, b:b{c:&c}, } } } fn main(){} 但它失败了: 错误[E0597]:`c`寿命不够长 -->src/main.rs:17:24 | 17 | b:b{c:&c},
struct A {
b: B,
c: C,
}
struct B {
c: &C,
}
struct C;
B.c
应该从A.c
借用
A->
b:b->
c:&c--从中借用--+
|
c:c,
c:c,
}
恳求{
fn新{
设c=c;
A{
c:c,
b:b{c:&c},
}
}
}
fn main(){}
但它失败了:
错误[E0597]:`c`寿命不够长
-->src/main.rs:17:24
|
17 | b:b{c:&c},
|^借来的价值不够长久
18 | }
19 | }
|-借来的价值仅在此处有效
|
注意:借用值必须在13:5在方法体上定义的生命周期“b”内有效。。。
-->src/main.rs:13:5
|
13 | fn新{
| ^^^^^^^^^^^^^^^^^^^^^
错误[E0382]:使用移动的值:`c`
-->src/main.rs:17:24
|
16 | c:c,
|-价值转移到这里
17 | b:b{c:&c},
|^移动后此处使用的值
|
=注意:发生移动是因为'c'具有'c'类型,该类型不实现'Copy'特性
我已经阅读了有关所有权的Rust文档,但我仍然不知道如何修复它。在与Manishearth和eddyb在#Rust IRC上进行了检查之后,我认为结构不可能存储对自身或自身一部分的引用。因此,在Rust的类型系统中,您尝试执行的操作是不可能的。实际上存在mor以上代码失败的原因不止一个。让我们把它分解一下,并探索一些解决方法 首先,让我们删除
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 },
};
}
它说的是,如果您将c1
分配给c
,您将其所有权移动到c
(即,您不能再通过c1
,只能通过c
)访问它。这意味着对c1
的所有引用将不再有效。但您的&c1
仍在范围内(在B中),因此编译器不能让您编译此代码
当编译器在错误消息中指出类型C
不可复制时,提示可能的解决方案。如果可以复制C
,则代码将有效,因为将c1
指定给C
将创建值的新副本,而不是移动原始副本的所有权
我们可以通过如下更改C
的定义使其可复制:
#[derive(Copy, Clone)]
struct C;
现在,上面的代码可以工作了。请注意,仍然正确的是:(我们在这里存储一个对值的引用和值的副本)。但这不仅仅是针对结构,而是所有权的工作方式
现在,如果您不想(或不能)使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 },
};
}
正如预期的那样,这是我们一生中的错误:
错误[E0597]:`c1`寿命不够长
-->src/main.rs:17:17
|
17 | c:&c1,
|^^借来的价值无法维持足够长的时间
...
20 | }
|-借来的价值仅在此处有效
|
注意:借用值必须在impl上定义的生命周期“a”内13:1有效。。。
-->src/main.rs:13:1
|
13 | impl{
| ^^^^^^^^^^^^^^
错误[E0597]:`c1`寿命不够长
-->src/main.rs:18:24
|
18 | b:b{c:&c1},
|^^借来的价值无法维持足够长的时间
19 | }
20 | }
|-借来的价值仅在此处有效
|
注意:借用值必须在impl上定义的生命周期“a”内13:1有效。。。
-->src/main.rs:13:1
|
13 | impl{
| ^^^^^^^^^^^^^^
这是因为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)
兄弟引用(即引用同一结构的一部分)在Rust中是不可能的。您(或其他任何人)知道有没有办法在新fn中创建“C”的同时让编译器满意?从技术上讲,您可以返回具有静态生存期的引用(
和静态C
),但这在实践中很少有用。有人知道现在是否有可能使用Pin
s来解决这一问题吗?文档中的示例演示了如何通过将&a T
替换为*const T
来实现类似的效果。但是,我看不到任何方法可以以某种方式替换我结束的类似情况对于这种情况,ed开始使用Arc
,这在我看来有点过分了,但我还没有看到一种更简单的方法。在堆上分配结构C而不是堆栈,并使用RC。嗨,Rufflewind,你知道如果不可能存储对结构本身一部分的引用,那么另一种方法是什么吗?@nybon最典型的解决方案就是这样的或者直接引用该值(即在上面的示例中,self.b.c
,完全省略self.c
),或者如果不需要,提供一种按需生成对c的引用的方法(这些引用可以正确地用结构的生存期进行注释)。
impl<'a> A<'a> {
fn new() -> A<'a> {
let c1 = C;
A {
c: &c1,
b: B { c: &c1 },
}
}
}
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)
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}}
}
}