【问题标题】:Rust: How to fix borrowed value does not live long enoughRust:如何修复借来的价值并没有足够长的时间
【发布时间】:2021-06-09 05:00:48
【问题描述】:

我有简单的客户端/服务器应用程序。我在服务器端从客户端接收消息,但我想将该响应从服务器发送到通道到其他文件,并且我收到错误“借用值的寿命不够长”。

我已经在堆栈溢出中搜索了类似的先前问题,但对生命周期没有足够的了解。是否有关于此主题的良好文档或简单示例?

现在,如果有人可以帮助我修复此代码(可能是编辑需要修复的代码部分),那将会很有帮助。

提前致谢。

服务器端:

use std::os::unix::net::UnixDatagram;
use std::path::Path;

fn unlink_socket (path: impl AsRef<Path>) {
    let path = path.as_ref();
    if Path::new(path).exists() {
        let result = std::fs::remove_file(path);
        match result {
            Err(e) => {
                println!("Couldn't remove the file: {:?}", e);
            },
            _ => {}
        }
    }
}

pub fn tcp_datagram_server() {
    pub static FILE_PATH: &'static str = "/tmp/datagram.sock";
    let (tx, rx) = mpsc::channel();
    let mut buf = vec![0; 1024];
    unlink_socket(FILE_PATH);
    let socket = match UnixDatagram::bind(FILE_PATH) {
        Ok(socket) => socket,
        Err(e) => {
            println!("Couldn't bind: {:?}", e);
            return;
        }
    };
    println!("Waiting for client to connect...");
    loop {
        let received_bytes = socket.recv(buf.as_mut_slice()).expect("recv function failed");
        println!("Received {:?}", received_bytes);
        let received_message = from_utf8(buf.as_slice()).expect("utf-8 convert failed");
        tx.clone().send(received_message);
    }
}

fn main() {
   tcp_datagram_server();
}

客户端:

use std::sync::mpsc;
use std::os::unix::net::UnixDatagram;
use std::path::Path;
use std::io::prelude::*;

pub fn tcp_datagram_client() {
    pub static FILE_PATH: &'static str = "/tmp/datagram.sock";
    let socket = UnixDatagram::unbound().unwrap();
    match socket.connect(FILE_PATH) {
        Ok(socket) => socket,
        Err(e) => {
            println!("Couldn't connect: {:?}", e);
            return;
        }
    };
    println!("TCP client Connected to TCP Server {:?}", socket);
    loop {
        socket.send(b"Hello from client to server").expect("recv function failed");
    }
}

fn main() {
   tcp_datagram_client();
}

我遇到的错误

error[E0597]: `buf` does not live long enough
  --> src/unix_datagram_server.rs:38:42
   |
38 |         let received_message = from_utf8(buf.as_slice()).expect("utf-8 convert failed");
   |                                          ^^^ borrowed value does not live long enough
...
41 | }
   | -
   | |
   | `buf` dropped here while still borrowed
   | borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `std::sync::mpsc::Sender`
   |
   = note: values in a scope are dropped in the opposite order they are defined

error: aborting due to previous error; 8 warnings emitted

【问题讨论】:

    标签: rust


    【解决方案1】:

    现在,如果有人可以帮助我修复此代码(可能是编辑需要修复的代码部分),那将会很有帮助。

    嗯,信息似乎很清楚。 send 完全按照它所说的去做,它通过通道发送参数。这意味着数据必须存在足够长的时间并“永远”保持有效(它需要在通道中以及在接收器从通道中获取时仍然有效且有效)。

    这里不是这样。 rustc 无法理解函数永远不会返回,并且无论如何它都会恐慌,最终会相同:函数将终止,这将使buf 无效。由于received_message 借用buf,这意味着received_message 在函数终止后不能有效。但此时消息仍会在通道中等待读取(或由接收者检索,但不知道是什么)。

    因此你的构造是不允许的。

    第二个问题是您在每个循环上都覆盖了缓冲区数据,这与破坏您在上一次迭代中发送的消息的效果相同,因此也不正确。尽管 Rust 也不会让你这样做:如果你解决第一个错误,它会告诉你有一个未完成的共享借用(通过通道发送的消息),所以你不能在接下来的迭代中修改后备缓冲区。

    解决方案非常简单:让每个迭代创建一个 owned 字符串(复制当前迭代的消息)并通过通道发送:

    tx.clone().send(received_message.to_string());
    

    此外,这些是更多风格/效率低下的评论,但是:

    • tx 上的 clone() 完全是多余的。拥有Clone 的发送者的意义在于能够从多个线程发送(因此通道名称中的 mp 用于多个生产者)。在这里你有一个线程,原始发件人工作正常。

    • .as_slice().as_mut_slice() 除非必要,否则很少使用,它们不在这里:数组引用强制切片,所以你可以只使用 &amp;mut buf&amp;buf。你为什么要在已经是一条道路的事情上打电话给Path::new?它没有任何作用,但也没有用。

    • 您的 sn-p 缺少多个导入,因此甚至无法按原样编译,这很烦人。

    • 从更统一的角度来看,错误通常打印在 stderr 上。在 Rust 中,eprintln 为您执行此操作(否则以与 println 相同的方式工作)。而且我不明白标记词汇嵌套staticpub 的目的。由于static 在函数内部,因此函数的兄弟姐妹甚至看不到它,更不用说外部调用者了。结果我最终得到了这个:

      use std::os::unix::net::UnixDatagram;
      use std::path::Path;
      use std::sync::mpsc;
      use std::str::from_utf8;
      
      fn unlink_socket (path: impl AsRef<Path>) {
          let path = path.as_ref();
          if path.exists() {
              if let Err(e) = std::fs::remove_file(path) {
                  eprintln!("Couldn't remove the file: {:?}", e);
              }
          }
      }
      
      static FILE_PATH: &'static str = "/tmp/datagram.sock";
      pub fn tcp_datagram_server() {
          unlink_socket(FILE_PATH);
          let socket = match UnixDatagram::bind(FILE_PATH) {
              Ok(socket) => socket,
              Err(e) => {
                  eprintln!("Couldn't bind: {:?}", e);
                  return;
              }
          };
      
          let (tx, _) = mpsc::channel();
          let mut buf = vec![0; 1024];
          println!("Waiting for client to connect...");
          loop {
              let received_bytes = socket.recv(&mut buf).expect("recv function failed");
              println!("Received {:?}", received_bytes);
              let received_message = from_utf8(&buf).expect("utf-8 convert failed");
              tx.send(received_message.to_string());
          }
      }
      

    【讨论】:

      【解决方案2】:

      编译器消息中有一个提示,作用域中的值按照定义它们的相反顺序删除,在示例中,buf 定义在 tx 之后,这意味着它将被删除 之前tx。由于对buf 的引用(以received_message 的形式)被传递给tx.send(),因此buf 的寿命应该比tx 更长,因此切换定义顺序将修复这个特定错误(即切换第19 行和 20)。

      【讨论】:

        猜你喜欢
        • 2020-07-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-29
        • 1970-01-01
        • 2015-10-18
        • 1970-01-01
        相关资源
        最近更新 更多