当我将值移动到生成的 Tokio 任务中时,为什么 Rust 生命周期很重要?
Why do Rust lifetimes matter when I move values into a spawned Tokio task?
我正在尝试创建一个结构来管理 Tokio 任务,其中一个 tokio::sync::mpsc::Sender
向任务发送输入,一个 tokio::sync::mpsc::Receiver
从任务接收输出,还有一个句柄我可以在最后加入。
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
// A type that implements BlockFunctionality consumes instances of T and
// produces either Ok(Some(U)) if an output is ready, Ok(None) if an output
// is not ready, or an Err(_) if the operation fails
pub trait BlockFunctionality<T, U> {
fn apply(&mut self, input: T) -> Result<Option<U>, &'static str>;
}
pub struct Block<T, U> {
pub tx_input: mpsc::Sender<T>,
pub rx_output: mpsc::Receiver<U>,
pub handle: JoinHandle<Result<(), &'static str>>,
}
impl<T: Send, U: Send> Block<T, U> {
pub fn from<B: BlockFunctionality<T, U> + Send>(b: B) -> Self {
let (tx_input, mut rx_input) = mpsc::channel(10);
let (mut tx_output, rx_output) = mpsc::channel(10);
let handle: JoinHandle<Result<(), &'static str>> = tokio::spawn(async move {
let mut owned_b = b;
while let Some(t) = rx_input.recv().await {
match owned_b.apply(t)? {
Some(u) => tx_output
.send(u)
.await
.map_err(|_| "Unable to send output")?,
None => (),
}
}
Ok(())
});
Block {
tx_input,
rx_output,
handle,
}
}
}
当我尝试编译它时,我得到了 B
的错误和其他两个类型参数的类似错误:
|
22 | pub fn from<B: BlockFunctionality<T, U> + Send>(b:B) -> Self {
| -- help: consider adding an explicit lifetime bound...: `B: 'static +`
...
27 | let handle:JoinHandle<Result<(), &'static str>> = tokio::spawn(async move {
| ^^^^^^^^^^^^ ...so that the type `impl std::future::Future` will meet its required lifetime bounds
我很难理解生命周期的问题出在哪里。按照我的理解,生命周期问题通常来自于寿命不够长的引用,但我正在移动值,而不是使用引用。我将 b
、rx_input
和 tx_output
移动到闭包中,并将 tx_input
、rx_output
和 handle
保留在调用范围中。有谁知道在这种情况下如何满足编译器?
那些值可能是引用或包含引用。引用类型是有效类型:B
可能是 &'a str
。或者 B
可以是 SomeType<'a>
,一种带有生命周期参数的类型,它本身包含一个 &'a str
.
说 B: 'static
意味着 B
的所有生命周期参数都比 'static
(ref) 长。例如,拥有自己的数据并因此没有生命周期参数(例如 String
)的类型满足此界限。但是 &'static str
也满足边界。
因为 tokio::spawn
创建的东西的生命周期不是静态范围的,所以它 requires a 'static
argument.
所以为了满足编译器的要求,添加 'static
边界:
impl<T: 'static + Send, U: 'static + Send> Block<T, U> {
pub fn from<B: 'static + BlockFunctionality<T, U> + Send>(b:B) -> Self {
我正在尝试创建一个结构来管理 Tokio 任务,其中一个 tokio::sync::mpsc::Sender
向任务发送输入,一个 tokio::sync::mpsc::Receiver
从任务接收输出,还有一个句柄我可以在最后加入。
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
// A type that implements BlockFunctionality consumes instances of T and
// produces either Ok(Some(U)) if an output is ready, Ok(None) if an output
// is not ready, or an Err(_) if the operation fails
pub trait BlockFunctionality<T, U> {
fn apply(&mut self, input: T) -> Result<Option<U>, &'static str>;
}
pub struct Block<T, U> {
pub tx_input: mpsc::Sender<T>,
pub rx_output: mpsc::Receiver<U>,
pub handle: JoinHandle<Result<(), &'static str>>,
}
impl<T: Send, U: Send> Block<T, U> {
pub fn from<B: BlockFunctionality<T, U> + Send>(b: B) -> Self {
let (tx_input, mut rx_input) = mpsc::channel(10);
let (mut tx_output, rx_output) = mpsc::channel(10);
let handle: JoinHandle<Result<(), &'static str>> = tokio::spawn(async move {
let mut owned_b = b;
while let Some(t) = rx_input.recv().await {
match owned_b.apply(t)? {
Some(u) => tx_output
.send(u)
.await
.map_err(|_| "Unable to send output")?,
None => (),
}
}
Ok(())
});
Block {
tx_input,
rx_output,
handle,
}
}
}
当我尝试编译它时,我得到了 B
的错误和其他两个类型参数的类似错误:
|
22 | pub fn from<B: BlockFunctionality<T, U> + Send>(b:B) -> Self {
| -- help: consider adding an explicit lifetime bound...: `B: 'static +`
...
27 | let handle:JoinHandle<Result<(), &'static str>> = tokio::spawn(async move {
| ^^^^^^^^^^^^ ...so that the type `impl std::future::Future` will meet its required lifetime bounds
我很难理解生命周期的问题出在哪里。按照我的理解,生命周期问题通常来自于寿命不够长的引用,但我正在移动值,而不是使用引用。我将 b
、rx_input
和 tx_output
移动到闭包中,并将 tx_input
、rx_output
和 handle
保留在调用范围中。有谁知道在这种情况下如何满足编译器?
那些值可能是引用或包含引用。引用类型是有效类型:B
可能是 &'a str
。或者 B
可以是 SomeType<'a>
,一种带有生命周期参数的类型,它本身包含一个 &'a str
.
说 B: 'static
意味着 B
的所有生命周期参数都比 'static
(ref) 长。例如,拥有自己的数据并因此没有生命周期参数(例如 String
)的类型满足此界限。但是 &'static str
也满足边界。
因为 tokio::spawn
创建的东西的生命周期不是静态范围的,所以它 requires a 'static
argument.
所以为了满足编译器的要求,添加 'static
边界:
impl<T: 'static + Send, U: 'static + Send> Block<T, U> {
pub fn from<B: 'static + BlockFunctionality<T, U> + Send>(b:B) -> Self {