如何将变量传递给异步函数?

How to pass a variable to an async function?

我已经从 smol 修改了一个 websocket 服务器 example 以将字符串传递给监听函数。

我收到一个错误:

main.rs(79, 17): this return type evaluates to the `'static` lifetime...
main.rs(62, 8): ...can't outlive the lifetime `'_` as defined on the function body at 62:8
main.rs(62, 5): Error originated from macro here``

我相信这是因为它被传递给了一个异步函数。对于正在发生的事情有更好的解释吗?有没有办法解决它?

修改后的版本:

Cargo.toml

[dependencies]
num_cpus = "1.13.0"
smol = "*"
anyhow = "*"
async-tungstenite = "*"
futures = "0.3.4"
tungstenite = "0.11.0"
async-native-tls = "0.3.3"
native-tls = "0.2.4"

main.rs

use std::net::{TcpListener, TcpStream};
use std::pin::Pin;
use std::task::{Context, Poll};
use std::thread;

use anyhow::{Context as _, Result};
use async_tungstenite::WebSocketStream;
use futures::prelude::*;
use smol::{Async, Task};
use tungstenite::Message;

/// Echoes messages from the client back to it.
async fn echo(mut stream: WsStream, s: &mut String) -> Result<()> {
    let msg = stream.next().await.context("expected a message")??;
    stream.send(Message::text(msg.to_string())).await?;
    s.push_str(" world!");
    Ok(())
}

/// Listens for incoming connections and serves them.
async fn listen(listener: Async<TcpListener>, s: &mut String) -> Result<()> {
    let host = format!("ws://{}", listener.get_ref().local_addr()?);
    println!("Listening on {}", host);

    loop {
        // Accept the next connection.
        let (stream, _) = listener.accept().await?;
        println!("Accepted client: {}", stream.get_ref().peer_addr()?);

        let stream = WsStream::Plain(async_tungstenite::accept_async(stream).await?);
        Task::spawn(echo(stream, s)).unwrap().detach();
    }
}

fn main() -> Result<()> {
    let mut s: String = String::from("Hello");

    // Create an executor thread pool.
    for _ in 0..num_cpus::get().max(1) {
        thread::spawn(|| smol::run(future::pending::<()>()));
    }

    // Start WS and WSS servers.
    smol::block_on(async {
        let ws = listen(Async::<TcpListener>::bind("127.0.0.1:9000")?, &mut s);
        ws.await?;
        Ok(())
    })
}

/// A WebSocket or WebSocket+TLS connection.
enum WsStream {
    /// A plain WebSocket connection.
    Plain(WebSocketStream<Async<TcpStream>>),
}

impl Sink<Message> for WsStream {
    type Error = tungstenite::Error;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).poll_ready(cx),
        }
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).start_send(item),
        }
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).poll_flush(cx),
        }
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).poll_close(cx),
        }
    }
}

impl Stream for WsStream {
    type Item = tungstenite::Result<Message>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        match &mut *self {
            WsStream::Plain(s) => Pin::new(s).poll_next(cx),
        }
    }
}

调用s时借用s的生命周期需要和echo返回的future一样长,因为它存储在其中。但是 Task::spawn 需要一个生命周期为 'static 的未来,所以这比在循环结束时返回它的作用域要长。您可能需要 Arc<Mutex<String>> 才能完成这项工作。