简体   繁体   中英

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 . If it can't do that, Rust will disallow the method call. 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.

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.
  • You need interior mutability (a Cell ) to allow mutating self.client even if self is a shared reference.
  • You need something other than a bare reference. An owned value or a shared ownership type like Rc or Arc , for example. These types sidestep the lifetime issue entirely. You can make the code generic over Borrow<T> to support them all at once.
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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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