Tokio / Tonic - How to fix this error: `self` has lifetime `'life0` but it needs to satisfy a `'static` lifetime requirement
Tokio / Tonic - How to fix this error: `self` has lifetime `'life0` but it needs to satisfy a `'static` lifetime requirement
我正在使用 Rust 和 tonic 构建 gRPC 服务器,并且 returns 流的函数存在一些问题。到目前为止,我看到的唯一例子是在函数内方便地创建 tx 和 rx 通道——但如果您需要从应用程序的其他部分接收数据,这并没有多大帮助。我有以下代码,但出现错误。
代码
use std::sync::Arc;
use std::sync::Mutex;
use futures::{Stream, StreamExt};
use tokio::sync::mpsc;
use tokio::sync::mpsc::{Sender, Receiver};
use tokio_stream::wrappers::ReceiverStream;
use tonic::transport::Server;
use tonic::{Request, Response, Status};use resourcemanager::{LineRequest, LineResponse, Position};
use resourcemanager::resource_manager_server::{ResourceManager, ResourceManagerServer};
pub mod resourcemanager {
tonic::include_proto!("resourcemanager");
}
#[derive(Debug)]
pub struct ResourceManagerService {
linear_rx: mpsc::Receiver<Position>,
linear_tx: mpsc::Sender<Position>
}
#[tonic::async_trait]
impl ResourceManager for ResourceManagerService {
async fn draw_line(&self, request: Request<LineRequest>) -> Result<Response<LineResponse>, Status> {
Ok(Response::new(LineResponse::default()))
}
type StreamLinearMotorMovementStream = ReceiverStream<Result<Position, Status>>;
async fn stream_linear_motor_movement(
&self,
request: Request<()>
) -> Result<Response<Self::StreamLinearMotorMovementStream>, Status> {
println!("Streaming motor movements");
let (tx, mut rx) = mpsc::channel(1);
tokio::spawn(async move {
while let Some(received) = self.linear_rx.recv().await {
tx.send(Ok(received.clone())).await.unwrap();
}
});
Ok(Response::new(ReceiverStream::new(rx)))
}
}
fn main() {
println!("Hello, world!");
}
错误
error[E0759]: `self` has lifetime `'life0` but it needs to satisfy a `'static` lifetime requirement
--> src/main.rs:30:10
|
30 | &self,
| ^^^^ this data with lifetime `'life0`...
...
36 | tokio::spawn(async move {
| ------------ ...is used and required to live as long as `'static` here
|
note: `'static` lifetime requirement introduced by this bound
--> /Users/xxxxxxxx/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.18.2/src/task/spawn.rs:127:28
|
127 | T: Future + Send + 'static,
| ^^^^^^^
此错误显示在 &self
下方:
async fn stream_linear_motor_movement(
&self,
request: Request<()>
)
错误消息基本上说明了一切。缩写:
async fn stream_linear_motor_movement(&self) {
let (tx, mut rx) = mpsc::channel(1);
tokio::spawn(async move {
while let Some(received) = self.linear_rx.recv().await {}
});
}
新生成的任务中的片段 self.linear_rx.recv().await
强制编译器将 self
移动到该闭包中,因此闭包可以访问 self.linear_rx
。然而,由于新任务 可以 运行 永远,它要求其捕获的上下文具有 'static
的生命周期,而 &self
具有有限的,可能比 'static
短,life0
的生命周期(无论结果如何)。这意味着您无法从新生成的任务中访问 self
(或从中派生的任何内容),因为无法保证在任务执行时它会存在。
你可以做的是将 ResourceManagerService
中的 linear_rx
移动到 Arc
中的 Arc
,stream_linear_motor_movement
中的 Arc
并移动克隆到闭包中。根据您要完成的目标,您还可以将 linear_rx
移动到 Option
和 .take()
中 Option
在 stream_linear_motor_movement
中,留下 None
在它的地方。在这两种情况下,您都将拥有的对象转移到新生成的任务中,该任务的生命周期不会短于 'static
。请注意 Arc
将允许多次调用 stream_linear_motor_movement
,而 Option
将只允许调用它一次(因为 linear_rx
在第一次调用时被移走) .
我正在使用 Rust 和 tonic 构建 gRPC 服务器,并且 returns 流的函数存在一些问题。到目前为止,我看到的唯一例子是在函数内方便地创建 tx 和 rx 通道——但如果您需要从应用程序的其他部分接收数据,这并没有多大帮助。我有以下代码,但出现错误。
代码
use std::sync::Arc;
use std::sync::Mutex;
use futures::{Stream, StreamExt};
use tokio::sync::mpsc;
use tokio::sync::mpsc::{Sender, Receiver};
use tokio_stream::wrappers::ReceiverStream;
use tonic::transport::Server;
use tonic::{Request, Response, Status};use resourcemanager::{LineRequest, LineResponse, Position};
use resourcemanager::resource_manager_server::{ResourceManager, ResourceManagerServer};
pub mod resourcemanager {
tonic::include_proto!("resourcemanager");
}
#[derive(Debug)]
pub struct ResourceManagerService {
linear_rx: mpsc::Receiver<Position>,
linear_tx: mpsc::Sender<Position>
}
#[tonic::async_trait]
impl ResourceManager for ResourceManagerService {
async fn draw_line(&self, request: Request<LineRequest>) -> Result<Response<LineResponse>, Status> {
Ok(Response::new(LineResponse::default()))
}
type StreamLinearMotorMovementStream = ReceiverStream<Result<Position, Status>>;
async fn stream_linear_motor_movement(
&self,
request: Request<()>
) -> Result<Response<Self::StreamLinearMotorMovementStream>, Status> {
println!("Streaming motor movements");
let (tx, mut rx) = mpsc::channel(1);
tokio::spawn(async move {
while let Some(received) = self.linear_rx.recv().await {
tx.send(Ok(received.clone())).await.unwrap();
}
});
Ok(Response::new(ReceiverStream::new(rx)))
}
}
fn main() {
println!("Hello, world!");
}
错误
error[E0759]: `self` has lifetime `'life0` but it needs to satisfy a `'static` lifetime requirement
--> src/main.rs:30:10
|
30 | &self,
| ^^^^ this data with lifetime `'life0`...
...
36 | tokio::spawn(async move {
| ------------ ...is used and required to live as long as `'static` here
|
note: `'static` lifetime requirement introduced by this bound
--> /Users/xxxxxxxx/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.18.2/src/task/spawn.rs:127:28
|
127 | T: Future + Send + 'static,
| ^^^^^^^
此错误显示在 &self
下方:
async fn stream_linear_motor_movement(
&self,
request: Request<()>
)
错误消息基本上说明了一切。缩写:
async fn stream_linear_motor_movement(&self) {
let (tx, mut rx) = mpsc::channel(1);
tokio::spawn(async move {
while let Some(received) = self.linear_rx.recv().await {}
});
}
新生成的任务中的片段 self.linear_rx.recv().await
强制编译器将 self
移动到该闭包中,因此闭包可以访问 self.linear_rx
。然而,由于新任务 可以 运行 永远,它要求其捕获的上下文具有 'static
的生命周期,而 &self
具有有限的,可能比 'static
短,life0
的生命周期(无论结果如何)。这意味着您无法从新生成的任务中访问 self
(或从中派生的任何内容),因为无法保证在任务执行时它会存在。
你可以做的是将 ResourceManagerService
中的 linear_rx
移动到 Arc
中的 Arc
,stream_linear_motor_movement
中的 Arc
并移动克隆到闭包中。根据您要完成的目标,您还可以将 linear_rx
移动到 Option
和 .take()
中 Option
在 stream_linear_motor_movement
中,留下 None
在它的地方。在这两种情况下,您都将拥有的对象转移到新生成的任务中,该任务的生命周期不会短于 'static
。请注意 Arc
将允许多次调用 stream_linear_motor_movement
,而 Option
将只允许调用它一次(因为 linear_rx
在第一次调用时被移走) .