为什么这种相互引用结构可以在 Rust 中以指定的生命周期工作?

Oyr*_*ren 4 lifetime rust borrow-checker

为什么下面的代码可以编译通过?

我希望 Rust 编译器能告诉我

设置参考时“借用的价值不够长”(store.barber.set(Some(&barber));

因为理发师的寿命比商店短。

use core::cell::Cell;

struct Shop<'a> {
    barber: Cell<Option<&'a Barber<'a>>>,
}

struct Barber<'a> {
    shop: Cell<Option<&'a Shop<'a>>>,
}

fn main() {
    let shop = Shop { barber: Cell::new(None) };
    {
        let barber = Barber { shop: Cell::new(Some(&shop))};
        shop.barber.set(Some(&barber));
    }
}
Run Code Online (Sandbox Code Playgroud)

操场

@jmb 的回答证实了我的假设(此处)。

代码示例来自这里。但我仍然不清楚为什么整个事情会起作用或者我的误解在哪里。

编辑/启示

我在 @Netwaves 答案上评论的代码。

万一链接不再起作用并澄清问题。

内部作用域只是为了让生命周期更加清晰。

用法看起来更像是这样:

use core::cell::Cell;

struct Shop<'a> {
    barber: Cell<Option<&'a Barber<'a>>>,
    shop_state: Cell<bool>,
}

impl<'a> Shop<'a> {
    fn change_barber_state(&self) {
        self.barber.get().unwrap().change_state();
    }

    fn change_state(&self) {
        self.shop_state.set(!self.shop_state.get());
    }
}

struct Barber<'a> {
    shop: Cell<Option<&'a Shop<'a>>>,
    barber_state: Cell<bool>,
}

impl<'a> Barber<'a> {
    fn change_state(&self) {
        self.barber_state.set(!self.barber_state.get());
    }

    fn change_shop_state(&self) {
        self.shop.get().unwrap().change_state();
    }
}

fn main() {
    let shop = Shop {
        barber: Cell::new(None),
        shop_state: Cell::new(false),
    };

    let barber = Barber {
        shop: Cell::new(Some(&shop)),
        barber_state: Cell::new(false),
    };
    shop.barber.set(Some(&barber));

    println!("{:?}", barber.barber_state);
    println!("{:?}", shop.shop_state);

    shop.change_barber_state();
    barber.change_shop_state();

    println!("{:?}", barber.barber_state);
    println!("{:?}", shop.shop_state);
}
Run Code Online (Sandbox Code Playgroud)

在相同的范围内,寿命是否相同?

我认为生命周期也是通过释放资源来给出的,这与声明的顺序相反。或者这仅在实施drop特征时才相关?

Net*_*ave 5

为什么这种相互引用结构可以在 Rust 中以指定的生命周期工作?

简短回答:

确实如此,因为根据您的代码,它实际上寿命足够长。

解释

问题(没问题)是您shop在内部作用域之后不再使用,因此编译器足够聪明,可以说您的程序没有任何问题。但如果你添加一个访问权限,他就会开始抱怨,并且有充分的理由:

fn main() {
    let shop = Shop { barber: Cell::new(None) };
    {
        let barber = Barber { shop: Cell::new(Some(&shop))};
        shop.barber.set(Some(&barber));
    }
    shop.barber.get();
}
Run Code Online (Sandbox Code Playgroud)

无法编译:

error[E0597]: `barber` does not live long enough
  --> src/main.rs:15:30
   |
15 |         shop.barber.set(Some(&barber));
   |                              ^^^^^^^ borrowed value does not live long enough
16 |     }
   |     - `barber` dropped here while still borrowed
17 |     shop.barber.get();
   |     ----------------- borrow later used here

Run Code Online (Sandbox Code Playgroud)

操场

关于问题扩展:

error[E0597]: `barber` does not live long enough
  --> src/main.rs:15:30
   |
15 |         shop.barber.set(Some(&barber));
   |                              ^^^^^^^ borrowed value does not live long enough
16 |     }
   |     - `barber` dropped here while still borrowed
17 |     shop.barber.get();
   |     ----------------- borrow later used here

Run Code Online (Sandbox Code Playgroud)

为什么你认为这不应该编译?

显然,直到主要完成时,两者的shop寿命barber都相同。在这种情况下,free 的顺序并不重要,因为编译器已经知道它们都不会再被使用,所以上面的代码是完全安全的。