如何将泛型类型参数移动到异步移动块中?

huangapple go评论82阅读模式
英文:

How to move generic typed parameter to an async move block?

问题

我正在尝试用Rust编写一些东西(我很喜欢但经验不多),发现了一个我不知道如何解决的障碍。

我的意图是生成一个异步任务,将初始状态作为参数传递。异步任务将接受该值(可以保持所有权)并进一步使用它。问题是初始值需要是一个泛型。但我收到了一个关于StateT生命周期的错误,并且我无法让编译器知道我想要将其移动/复制到异步块中。

async fn start<StateT>(initial_value: StateT) -> impl futures::Future
where
    StateT: Send,
{
    tokio::spawn(async move {
        process(initial_value);
    })
}

我尝试过将StateT: Copy + Send + Sync等等,但编译器不喜欢。只有'static能够编译通过,但我想这不是正确的(它不是我将传递的常量,而是某个任意的结构体)。

错误消息是:

error[E0310]: the parameter type `StateT` may not live long enough
 --&gt; src/workflow2.rs:7:5
  |
7 | /     tokio::spawn(async move {
8 | |         process(initial_value);
9 | |     })
  | |______^ ...so that the type `StateT` will meet its required lifetime bounds
  |
help: consider adding an explicit lifetime bound...
  |
5 |     StateT: Send + 'static,
  |                  +++++++++

如果我尝试传递i32String而不是泛型,它可以正常工作。所以我想我可能是缺少一些适用于StateT的特质约束,以提供所缺少的内容。

英文:

I'm trying to write something in Rust (which I love but don't have much experience yet) and found a hurdle I have no idea how to sort out.

My intention is to spawn an asynchronous task passing an initial state as parameter. The asynchronous task will take that value (it can keep ownership of it) and use it further. Thing is the initial value needs to be a generic. And I get an error complaining about the lifetime of StateT and I cannot let the compiler know that I want to move it / copy it to the async block.

async fn start&lt;StateT&gt;(initial_value: StateT) -&gt; impl futures::Future
where
    StateT: Send,
{
    tokio::spawn(async move {
        process(initial_value);
    })
}

I tried making StateT: Copy + Send + Sync, etc but it doesn't like it. Only &#39;static works but I guess that's not right (it's not a constant that I will pass, but some arbitrary struct).

The error message is:

error[E0310]: the parameter type `StateT` may not live long enough
 --&gt; src/workflow2.rs:7:5
  |
7 | /     tokio::spawn(async move {
8 | |         process(initial_value);
9 | |     })
  | |______^ ...so that the type `StateT` will meet its required lifetime bounds
  |
help: consider adding an explicit lifetime bound...
  |
5 |     StateT: Send + &#39;static,
  |                  +++++++++

If I try passing an i32 or a String instead of the generic it works just fine. So I guess I'm missing some trait bound for StateT that provides what's missing.

答案1

得分: 5

只有 'static 起作用,但我猜这不对(它不是我要传递的常量,而是某个任意的结构体)。

这是Rust 常见生命周期误解#2T: 'static 不意味着 T 存活于整个程序,并且更不意味着 T 是一个常量。它仅表示 T 是一个完全独立的类型,不借用任何其他数据。因此,在这里使用 StateT: 'static 是正确的做法:

async fn start<StateT>(initial_value: StateT) -> impl futures::Future
where
    StateT: Send + 'static,
{
    tokio::spawn(async move {
        process(initial_value);
    })
}
英文:

> Only 'static works but I guess that's not right (it's not a constant that I will pass, but some arbitrary struct).

This is common Rust lifetime misconception #2: T: &#39;static does not mean that T lives for the entire program, and even less that T is a constant. It only means that T is a fully self-contained type and that it doesn't borrow any other data. So StateT: &#39;static is the right thing to do here:

async fn start&lt;StateT&gt;(initial_value: StateT) -&gt; impl futures::Future
where
    StateT: Send + &#39;static,
{
    tokio::spawn(async move {
        process(initial_value);
    })
}

huangapple
  • 本文由 发表于 2023年6月26日 13:07:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76553656.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定