rust 多借结构

ff29svar  于 2022-11-24  发布在  其他
关注(0)|答案(1)|浏览(102)

我是Rust的新手,我正在尝试实现一个简单的TCP服务器,它会向我发送一个实时图像。因此,我使用这个crate https://crates.io/crates/tinybmp作为RawBmp类型。现在,我正在努力理解Rust的一些功能。或者说,我还在尝试弄清楚如何在“Rust方式”中完成这一点。

pub struct TCPBasePackage {
    haspayload: bool,
    pkgbytes: Vec<u8>,
}

impl TCPBasePackage {
    pub const CMD: i32 = 0;

    pub fn new() -> TCPBasePackage {
        TCPBasePackage { haspayload: false, pkgbytes: Vec::new()}
    }
}

impl TCPPackage for TCPBasePackage {
    fn serialize(&mut self) -> &[u8] {
        self.pkgbytes.append(&mut self.get_command().to_be_bytes().to_vec());        
        self.pkgbytes.append(&mut [u8::from(self.haspayload)].to_vec());
        self.pkgbytes.as_slice()
    }

    fn read_from_stream(&mut self, mut stream: &TcpStream) -> Vec<u8> {
        let mut vec: Vec<u8> = Vec::new();
        let mut buf_pkg: [u8; 5] = [0; 5];
        stream.read_exact(&mut buf_pkg).unwrap();
        vec.append(&mut buf_pkg.to_vec());
        self.pkgbytes = vec.to_vec();
        return self.pkgbytes.clone();
    }

    fn deserialize(&mut self, buff: &[u8]) -> i32 {
        self.haspayload = buff[4] != 0;
        return 5;
    }

    fn get_command(&self) -> i32 {
        TCPBasePackage::CMD
    }
}

pub struct MsgLiveImage<'a> {
    tcppackage: TCPBasePackage,
    imgbytes: Vec::<u8>,
    img: RawBmp<'a>,
}

impl<'a> MsgLiveImage<'a> {
    pub const CMD: i32 = 2;

    pub fn new() -> MsgLiveImage<'static> {
        MsgLiveImage { 
tcppackage: TCPBasePackage { haspayload: false, pkgbytes: Vec::new() },
            imgbytes: Vec::new(),
            img: RawBmp::from_slice(&[]).unwrap()
        }
    }

    pub fn set_image_data(&'a mut self, data: Vec::<u8>) {
        self.imgbytes = data;
        self.img = RawBmp::from_slice(&self.imgbytes.as_slice()).unwrap();
    }

}

在我的应用程序的某个函数中我想这样做:

fn write_response_to_stream(
    mut request: &Box<dyn mytcp::TCPPackage>,
    mut stream: &TcpStream,
    raspicam: &Arc<Mutex<camserv::CamServ>>,
) -> Result<Box<dyn mytcp::TCPPackage>, &'static str> {
    match request.get_command() {
        mytcp::MsgLiveImage::CMD => {
            let mut pkg = mytcp::MsgLiveImage::new();
            {
                {
                    let tmpcam = raspicam.lock().unwrap(); // lock the camera server 
                    let tmpbuff = tmpcam.imgbuff.lock().unwrap(); // lock the buffer of last image
                    pkg.set_image_data((*tmpbuff).clone()); // make copy of my image and transfer ownership of that copy to the package struct
                }
                {
                    let sbuff = pkg.serialize();
                    stream.write(&sbuff);
                }
                stream.flush();
            }
            Ok(Box::new(pkg)) // return the response package
        }
        _ => Err("Unknown request package"),
    }
}

但问题是编译器抱怨多次借用pkg-变量。以及将pkg移出范围(我了解到这应该可以通过将其 Package 在Box中来实现。有人能解释一下为什么第一次可变借用即使在方法返回后仍然持续吗?我怎样才能实现在我的结构上调用多个方法而不发生这些借用冲突呢?
来自rustc的错误:

error[E0499]: cannot borrow `pkg` as mutable more than once at a time
  --> src/raspiserv/mod.rs:90:33
   |
87 |                     pkg.set_image_data((*tmpbuff).clone());
   |                     -------------------------------------- first mutable borrow occurs here
...
90 |                     let sbuff = pkg.serialize();
   |                                 ^^^^^^^^^^^^^^^ second mutable borrow occurs here
...
95 |             Ok(Box::new(pkg))
   |             ----------------- returning this value requires that `pkg` is borrowed for `'static`

error[E0515]: cannot return value referencing local variable `pkg`
  --> src/raspiserv/mod.rs:95:13
   |
87 |                     pkg.set_image_data((*tmpbuff).clone());
   |                     -------------------------------------- `pkg` is borrowed here
...
95 |             Ok(Box::new(pkg))
   |             ^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error[E0505]: cannot move out of `pkg` because it is borrowed
  --> src/raspiserv/mod.rs:95:25
   |
87 |                     pkg.set_image_data((*tmpbuff).clone());
   |                     -------------------------------------- borrow of `pkg` occurs here
...
95 |             Ok(Box::new(pkg))
   |             ------------^^^--
   |             |           |
   |             |           move out of `pkg` occurs here
   |             returning this value requires that `pkg` is borrowed for `'static`
jdgnovmf

jdgnovmf1#

问题出在你的set_image_data

pub fn set_image_data(&'a mut self, data: Vec::<u8>) {
        self.imgbytes = data;
        self.img = RawBmp::from_slice(&self.imgbytes.as_slice()).unwrap();
    }

'a的生存期内借用self,只要它里面的RawBmp有效,那么借用的时间和结构体的时间一样长.
你所拥有的是一个自我引用结构,请参见他们的问题,以获得如何解决这个问题的建议。
您可能只需要将imgMsgLiveImage中删除,并将其替换为一个方法:

impl MsgLiveImage {
    pub fn as_img<'a>(&'a self) -> Result<RawBmp<'a>, ParseError> {
        RawBmp::from_slice(&self.imgbytes.as_slice())
    }
}

甚至可以省略其中的寿命。

相关问题