admin管理员组

文章数量:1404924

I'm building a client for an API targeting an embedded system. I'm using the reqwless HTTP client library running on top of esp-hal based stack. On top of reqwless, I want to implement automatic reconnection if the connection is reset but I'm running into issues with lifetimes. This is probably due to the fact that I essentially end up with a version of a self-referencing struct. I created a minimal example illustrating the problem:

//
// NOT MY CODE:
//

struct Error;

struct ClientResources {/* ... */}

struct Client {
    res: ClientResources,
}

impl Client {
    pub fn connect(&mut self) -> Socket<'_> {
        Socket { res: &mut self.res }
    }
}

struct Socket<'a> {
    res: &'a mut ClientResources,
}

impl<'a> Socket<'a> {
    pub fn send(&mut self, msg: String) -> Result<(), Error> {
        todo!();
    }
}

//
// MY CODE:
//

struct ReconnectingSocket<'a> {
    client: &'a mut Client,
    socket: Option<Socket<'a>>,
}

impl<'a> ReconnectingSocket<'a> {
    pub fn send(&mut self, msg: String) {
        loop {
            let socket = match self.socket.as_mut() {
                Some(sock) => sock,
                None => {
                    self.socket = Some(self.client.connect());
                    self.socket.as_mut().unwrap()
                }
            };

            if let Ok(_) = socket.send(msg.clone()) {
                return;
            } else {
                self.socket = None;
            }
        }
    }
}

The error from the compiler:

error[E0499]: cannot borrow `*self.client` as mutable more than once at a time
  --> src/main.rs:36:40
   |
30 | impl<'a> ReconnectingSocket<'a> {
   |      -- lifetime `'a` defined here
...
36 |                     self.socket = Some(self.client.connect());
   |                                        ^^^^^^^^^^^----------
   |                                        |
   |                                        `*self.client` was mutably borrowed here in the previous iteration of the loop
   |                                        argument requires that `*self.client` is borrowed for `'a`

error: lifetime may not live long enough
  --> src/main.rs:36:40
   |
30 | impl<'a> ReconnectingSocket<'a> {
   |      -- lifetime `'a` defined here
31 |     pub fn send(&mut self, msg: String) {
   |                 - let's call the lifetime of this reference `'1`
...
36 |                     self.socket = Some(self.client.connect());
   |                                        ^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`

It is often said that Rust does not allow self-referencing structs because then they cannot be moved. In this case, ReconnectingSocket is not really referencing a value within itself, it references a reference within itself. This struct is perfectly movable but it seems like the same mechanism that prevents a self-referencing struct also prevents this solution.

How can I get around this problem? Is there some sort of trick? Or do I need to rething entirely how to make an auto reconnecting API?

本文标签: rustLifetime issue when implementing reconnecting socketStack Overflow