【问题标题】:Borrowed value does not live long enough with a Tokio future借来的价值与 Tokio 未来的寿命不长
【发布时间】:2019-04-10 10:44:50
【问题描述】:

我正在尝试使用 Rust 和 tokio 编写一个简单的 HTTP 服务器。

在我想发送响应之前一切正常。

代码如下:

use std::fs;
use std::sync::Arc;
use tokio::net::TcpListener; // 0.1.15
use tokio::prelude::*;

fn main() {
    let addr = "0.0.0.0:8080".parse().unwrap();
    let listener = TcpListener::bind(&addr).expect("unable to bind TCP listener");

    let incoming = listener.incoming();

    let server = incoming
        .map_err(|e| eprintln!("accept failed = {:?}", e))
        .for_each(|socket| {
            println!(
                "Connection established: from {:?} to {:?}",
                socket.peer_addr(),
                socket.local_addr()
            );
            let bytes = vec![0; 512];
            let processor = tokio::io::read(socket, bytes)
                .and_then(|(socket, bytes, _size)| {
                    println!("Request: {}", String::from_utf8_lossy(&bytes[..]));
                    let contents = fs::read_to_string("hello.html").unwrap();
                    let response = Arc::new(format!("HTTP/1.1 200 OK\r\n\r\n{}", contents));
                    let response = response.clone();
                    tokio::io::write_all(socket, response.as_bytes()).and_then(|_| Ok(()))
                })
                .map_err(|_| ());
            tokio::spawn(processor);
            Ok(())
        });

    tokio::run(server);
}
error[E0597]: `response` does not live long enough
  --> src/main.rs:27:50
   |
27 |                     tokio::io::write_all(socket, response.as_bytes()).and_then(|_| Ok(()))
   |                                                  ^^^^^^^^ borrowed value does not live long enough
28 |                 })
   |                 - `response` dropped here while still borrowed

我必须如何声明响应才能活得够久?

【问题讨论】:

  • 你为什么不直接使用into_bytes,而不是用arc包裹并传递借来的字节数组? Playground
  • 成功了。谢谢。但我不明白为什么用 arc 包裹没有。

标签: rust borrow-checker rust-tokio


【解决方案1】:

你怎样才能让它发挥作用?

正如我在评论中指出的那样:使用 into_bytes,而不是使用 Arc 包装并传递借用的字节数组。

Playground


@大卫:

但我不明白为什么用 arc 包裹没有。

Arc 计算内部对象的引用:

  • 当你clone()时它会增加引用
  • Arc所有者 被删除时,它会减少引用。
  • 当引用计数减少到 0 时,它会从内存中删除

在您的情况下,Arc 的所有者被命名为 responseresponse 在范围内创建并在同一范围的末尾删除。它的引用计数在创建时为 1,丢弃后变为 0。但是您在 Future 中传递了 Arc 的引用,就在它从内存中删除之前。

请注意,write_all() 创建了一个Future,而Future 带有您的Arc 的引用,该引用在Future 执行之前从内存中删除。

注意WriteAll 可以拥有 borrowedmoved 值的所有权,它需要一个可以转换为 @987654338 的通用参数@。

【讨论】:

  • 对不起,我还是不明白 Arc 和 into_bytes() 的区别。如果我理解正确,Arc 在超出范围时会被丢弃,因为它尚未执行。即使声明了一个 response2=response.clone()。但是使用 into_bytes() 也不应该工作。它会创建一个响应,该响应是一个在未来执行之前超出范围的向量。区别在哪里?
  • @David 只需 as_bytes Future(WriteAll) 借用字节,into_bytes Future 获得字节的所有权。由于Future 拥有所有权,字节不会在作用域中被丢弃,因此它保证它将在Future 或执行后被丢弃。
  • @David 还有write_all 需要一个可以转换为切片的通用参数,因此您可以使用借用或移动的参数来调用write_all
  • 是的,现在区别很明显了。谢谢你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
  • 2020-01-07
  • 2019-11-29
  • 1970-01-01
相关资源
最近更新 更多