不清楚如何正确定义结构的生命周期

Not clear how to correctly define lifetime for struct

我有 TCP 客户端,它处理一些处理程序。我需要在它们之间共享数据,所以我为这种情况实现了 Session 结构:

struct Session<'a> {
    pub session_key: Option<&'a Vec<u8>>,
    pub username: Option<&'a str>,
    pub password: Option<&'a str>,
}

impl Session {
    pub fn new() -> Self {
        Self {
            session_key: None,
            username: None,
            password: None,
       }
    }
}

我添加了引用访问以允许借用数据。 但是,当我尝试在我的代码中使用这个结构时,出现了与生命周期相关的错误:

implicit elided lifetime not allowed here

cannot infer an appropriate lifetime for borrow expression due to conflicting requirements

这是minimal sandbox implementation

以防万一这是我的示例代码(大部分与我的真实应用程序相似):

// data which store values that I need to share between handlers
struct Session<'a> {
    pub session_key: Option<&'a Vec<u8>>,
    pub username: Option<&'a str>,
    pub password: Option<&'a str>,
}

// not sure if this correct to set &None below, where to put the lifetime here ?
impl Session {
    pub fn new() -> Self {
        Self {
            session_key: None,
            username: None,
            password: None,
        }
    }
}

// what handler return
pub enum HandlerResponse {
    Packet(Vec<u8>),
    Void,
}

// handler params
pub struct HandlerInput<'a> {
    session: &'a mut Session<'a>,
    data: Option<Vec<u8>>
}

pub struct Client<'a> {
    stream: Option<TcpStream>,
    buffer: [u8; 4096],
    session: Session<'a>,
}

// public methods
impl<'a> Client<'a> {
    pub fn new() -> Self {
        Self {
            stream: None,
            buffer: [0u8; 4096],
            session: Session::new(),
        }
    }

    pub fn connect(&mut self, host: &str, port: i16) {
        let addr = format!("{}:{}", host, port);
        match TcpStream::connect(&addr) {
            Ok(stream) => {
                self.stream = Some(stream);
                println!("Connected to {}", addr);
            },
            _ => {
                println!("Cannot connect");
            },
        }
    }

    pub fn handle_connection(
        &mut self, 
        handlers: Vec<fn(HandlerInput
    ) -> Result<u8, Error>>) {
        for handler in handlers {
            self.process(handler);
        }
    }
}

// private methods
impl<'a> Client<'a> {
    fn process<F>(&mut self, handler: F)
    where
        F: Fn(HandlerInput) -> Result<HandlerResponse, Error>
    {
        let response: Result<HandlerResponse, Error> = match self.handle_read() {
            Ok(server_response) => handler(HandlerInput {
                session: &mut self.session,
                data: Some(server_response),
            }),
            _ => handler(HandlerInput {
                session: &mut self.session,
                data: None,
            })
        };

        match response.unwrap() {
            HandlerResponse::Packet(data) => {
                self.handle_write(data).unwrap();
            },
            HandlerResponse::Void => {},
        }
    }

    fn handle_write(&mut self, packet: Vec<u8>) -> Result<(), Error> {
        let mut stream = self.stream.as_ref().unwrap();

        match stream.write(&packet) {
            Ok(_) => Ok(()),
            _ => Err(Error::new(ErrorKind::Other, "Write error")),
        }
    }

    fn handle_read(&mut self) -> Result<Vec<u8>, Error> {
        let mut stream = self.stream.as_ref().unwrap();
        let mut buffer = self.buffer.as_mut();

        match stream.read(&mut buffer) {
            Ok(bytes_count) => {
                return Ok(buffer[ .. bytes_count].to_vec());
            },
            _ => Err(Error::new(ErrorKind::Other, "Read error")),
        }
    }
}

当我将生命周期放在 Client 结构上,然后将生命周期放在 &'a mut self 上时,我得到一个错误:

cannot infer an appropriate lifetime for borrow expression due to conflicting requirements

你能在这里解释一下如何修复生命周期吗?

更新: 我需要在 Session 中引用,因为我想在处理程序中使用会话的值,如果我不使用引用,我会收到错误消息:

move occurs because input.session.session_key has type Option<Vec<u8>>, which does not implement the Copy trait

代码我是怎么用的 Session:

fn handler(input: HandlerInput) {
    let hasher = Sha1::new();
    let digest = hasher
        .chain(input.session.username.unwrap())
        .chain(input.session.session_key.unwrap())
        .finalize();
}

有时我还需要修改处理程序中的输入,例如:

let mut session = input.session;
session.session_key = Some(srp_client.session_key());

我可以看到两个问题:

  • 您的简短示例代码缺少生命周期注释
  • 你的较长代码是借用几乎不可能实现的实现,因此我怀疑这个问题是XY-problem

快速修复您的短代码示例

您的 impl 缺少生命周期:

pub struct Session<'a> {
    pub session_key: Option<&'a Vec<u8>>,
    pub username: Option<&'a str>,
    pub password: Option<&'a str>,
}

impl<'a> Session<'a> {
    pub fn new() -> Self {
        Self {
            session_key: None,
            username: None,
            password: None,
       }
    }
}

您可能真正想要的

所以我的问题是,为什么首先要为 Session 使用借用? 从技术上讲,您只需要 HandlerInput 中的参考。然后,两个处理程序看到相同的 Session 对象进行修改。

use std::io::{Error, ErrorKind, Read, Write};
use std::net::TcpStream;

// data which store values that I need to share between handlers
struct Session {
    pub session_key: Option<Vec<u8>>,
    pub username: Option<String>,
    pub password: Option<String>,
}

// not sure if this correct to set &None below, where to put the lifetime here ?
impl Session {
    pub fn new() -> Self {
        Self {
            session_key: None,
            username: None,
            password: None,
        }
    }
}

// what handler return
pub enum HandlerResponse {
    Packet(Vec<u8>),
    Void,
}

// handler params
pub struct HandlerInput<'a> {
    session: &'a mut Session,
    data: Option<Vec<u8>>,
}

pub struct Client {
    stream: Option<TcpStream>,
    buffer: [u8; 4096],
    session: Session,
}

// public methods
impl Client {
    pub fn new() -> Self {
        Self {
            stream: None,
            buffer: [0u8; 4096],
            session: Session::new(),
        }
    }

    pub fn connect(&mut self, host: &str, port: i16) {
        let addr = format!("{}:{}", host, port);
        match TcpStream::connect(&addr) {
            Ok(stream) => {
                self.stream = Some(stream);
                println!("Connected to {}", addr);
            }
            _ => {
                println!("Cannot connect");
            }
        }
    }

    pub fn handle_connection(
        &mut self,
        handlers: Vec<fn(HandlerInput) -> Result<HandlerResponse, Error>>,
    ) {
        for handler in handlers {
            self.process(handler);
        }
    }
}

// private methods
impl Client {
    fn process<F>(&mut self, handler: F)
    where
        F: Fn(HandlerInput) -> Result<HandlerResponse, Error>,
    {
        let response: Result<HandlerResponse, Error> = match self.handle_read() {
            Ok(server_response) => handler(HandlerInput {
                session: &mut self.session,
                data: Some(server_response),
            }),
            _ => handler(HandlerInput {
                session: &mut self.session,
                data: None,
            }),
        };

        match response.unwrap() {
            HandlerResponse::Packet(data) => {
                self.handle_write(data).unwrap();
            }
            HandlerResponse::Void => {}
        }
    }

    fn handle_write(&mut self, packet: Vec<u8>) -> Result<(), Error> {
        let mut stream = self.stream.as_ref().unwrap();

        match stream.write(&packet) {
            Ok(_) => Ok(()),
            _ => Err(Error::new(ErrorKind::Other, "Write error")),
        }
    }

    fn handle_read(&mut self) -> Result<Vec<u8>, Error> {
        let mut stream = self.stream.as_ref().unwrap();
        let mut buffer = self.buffer.as_mut();

        match stream.read(&mut buffer) {
            Ok(bytes_count) => {
                return Ok(buffer[..bytes_count].to_vec());
            }
            _ => Err(Error::new(ErrorKind::Other, "Read error")),
        }
    }
}

fn handler1(input: HandlerInput) -> Result<HandlerResponse, Error> {
    Ok(HandlerResponse::Void)
}

fn handler2(input: HandlerInput) -> Result<HandlerResponse, Error> {
    Ok(HandlerResponse::Void)
}

fn main() {
    let mut client = Client::new();
    client.connect("127.0.0.1", 8080);
    client.handle_connection(vec![handler1, handler2]);
}

编译正常,应该可以工作。