Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 对生锈的结构使用寿命的正确方法是什么?_Rust_Lifetime - Fatal编程技术网

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}}
    }
}