6

Rust为什么不能在同一Struct中存储值和对该值的引用?

 1 year ago
source link: https://www.jdon.com/66947.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Rust为什么不能在同一Struct中存储值和对该值的引用?

我们看一下这个的简单实现

struct Parent {
    count: u32,
}

struct Child<'a> {
    parent: &'a Parent,
}

struct Combined<'a> {
    parent: Parent,
    child: Child<'a>,
}

impl<'a> Combined<'a> {
    fn new() -> Self {
        let parent = Parent { count: 42 };
        let child = Child { parent: &parent };

        Combined { parent, child }
    }
}

fn main() {}

出现错误:

error[E0515]: cannot return value referencing local variable `parent`
  --> src/main.rs:19:9
   |
17 |         let child = Child { parent: &parent };
   |                                     ------- `parent` is borrowed here
18 | 
19 |         Combined { parent, child }
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error[E0505]: cannot move out of `parent` because it is borrowed
  --> src/main.rs:19:20
   |
14 | impl<'a> Combined<'a> {
   |      -- lifetime `'a` defined here
...
17 |         let child = Child { parent: &parent };
   |                                     ------- borrow of `parent` occurs here
18 | 
19 |         Combined { parent, child }
   |         -----------^^^^^^---------
   |         |          |
   |         |          move out of `parent` occurs here
   |         returning this value requires that `parent` is borrowed for `'a`

为了完全理解这个错误,你必须思考数值在内存中是如何表示的,以及当你移动这些数值时会发生什么。

这正是Rust生命期/生存期(lifetimes)所要防止的问题。
生命期是一个元数据,它允许你和编译器知道一个值在其当前内存位置的有效时间。这是一个重要的区别,因为这是Rust新手常犯的一个错误。

Rust的生命期/生存期并不是指一个对象被创建和被销毁之间的时间段

打个比方,可以这样想:在一个人的一生中,他们会居住在许多不同的地方,每个地方都有一个不同的地址。锈的一生关注的是你目前居住的地址,而不是你将来什么时候死(尽管死亡也会改变你的地址)。每次你搬家都是相关的,因为你的地址不再有效了。

同样重要的是要注意,生命期不会改变你的代码;你的代码控制生命期,你的生命期不控制代码。

精辟的说法是 "生命期是描述性的,不是规定性的"。

让我们用一些行号来注释Combined::new,我们将用这些行号来强调生命期:

{                                          // 0
    let parent = Parent { count: 42 };     // 1
    let child = Child { parent: &parent }; // 2
                                           // 3
    Combined { parent, child }             // 4
}                                          // 5
  • parent 的具体生存期是从1到4,包括在内(我将其表示为[1,4])。
  • child的具体生命周期/生存期是[2,4],
  • 而返回return 值的具体生命周期是[4,5]。

请注意,child本身的生存期是[2,4],但它引用的是一个生存期为[1,4]的值。只要引用值在引用值失效之前失效就可以。
问题出在:我们试图从块{}中返回return child时,而返回return 值的具体生命周期是[4,5],多了一个5,这将 "过度延长 "child生命周期[2,4],超过其自然生存期长度。

如何解决?
最简单和最推荐的解决方案是不要将这些东西放在同一结构中:
不要在同一Struct中存储值和对该值的引用。
将拥有数据的类型放在一个结构中,然后提供允许您根据需要获取引用或包含引用的对象的方法。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK