简体   繁体   English

Rust 中在结构中存储引用的正确方法

[英]Proper way in Rust to store a reference in a struct

What is the proper way to store a reference in a struct and operate on it given this example:在这个例子中,将引用存储在结构中并对其进行操作的正确方法是什么:

// Trait that cannot be changed
pub trait FooTrait {
    pub fn open(&self, client: &SomeType);
    pub fn close(&self);
}

pub struct Foo {
    // HOW TO STORE IT HERE???
    // client: &SomeType,
}

impl FooTrait for Foo {
    pub fn open(&self, client: &SomeType) {
        // HOW TO SAVE IT HERE?
        // NOTE that &self cannot be changed into &mut self because the trait cannot be modified
        // smth like self.client = client;
    }

    pub fn close(&self) {
        // HOW TO DELETE IT HERE?
        // NOTE that &self cannot be changed into &mut self because the trait cannot be modified
    }
}

Is there a design pattern that could fit to my snippet?是否有适合我的代码片段的设计模式?

This is horribly complicated on its surface because of lifetime issues.由于寿命问题,这在表面上非常复杂。 Rust is designed to guarantee memory safety, but this pattern creates an untenable situation where the caller of FooTrait::open() needs some way to tell Rust that the client borrow will outlive *self . Rust 旨在保证 memory 的安全,但这种模式造成了一种难以维持的情况,即FooTrait::open()的调用者需要某种方式来告诉 Rust client借用的时间将超过*self If it can't do that, Rust will disallow the method call.如果它不能这样做,Rust 将不允许该方法调用。 Actually making this work with references is probably not feasible, as Foo needs a lifetime parameter, but the code that creates the Foo may not know the appropriate lifetime parameter.实际上,使用引用进行这项工作可能是不可行的,因为Foo需要一个生命周期参数,但创建Foo的代码可能不知道合适的生命周期参数。

You can make this pattern work by combining a few things, but only if you can modify the trait.可以通过组合一些东西来使这个模式起作用,但前提是你可以修改特征。 If you can't change the definition of the trait, then what you are asking is impossible.如果您不能更改特征的定义,那么您所要求的是不可能的。

  • You need an Option so that close can clear the value.您需要一个Option以便close可以清除该值。
  • You need interior mutability (a Cell ) to allow mutating self.client even if self is a shared reference.您需要内部可变性(a Cell )以允许改变self.client即使self是共享引用。
  • You need something other than a bare reference.除了简单的参考,您还需要其他东西。 An owned value or a shared ownership type like Rc or Arc , for example.拥有的值或共享的所有权类型,例如RcArc These types sidestep the lifetime issue entirely.这些类型完全回避了生命周期问题。 You can make the code generic over Borrow<T> to support them all at once.您可以使代码在Borrow<T>上通用以同时支持它们。
use std::cell::Cell;
use std::borrow::Borrow;

pub trait FooTrait {
    fn open(&self, client: impl Borrow<SomeType> + 'static);
    fn close(&self);
}

pub struct SomeType;

pub struct Foo {
    client: Cell<Option<Box<dyn Borrow<SomeType>>>>,
}

impl FooTrait for Foo {
    fn open(&self, client: impl Borrow<SomeType> + 'static) {
        self.client.set(Some(Box::new(client)));
    }

    fn close(&self) {
        self.client.set(None);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM