英文:
How can I make a cloned Arc live long enough for a tokio task in Rust?
问题
我在说服编译器确保某些变量的生命周期足够长。
以下是我的代码:
use trust_dns_resolver::{
config::{ResolverConfig, ResolverOpts},
TokioAsyncResolver,
};
fn main() {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(async {
let cb_domain_iter = vec!["example.com.", "google.com.", "facebook.com."];
let resolver = Arc::new(
TokioAsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default())
.expect("Could not create resolver"),
);
let tasks = cb_domain_iter.iter().map(move |domain| {
let resolver_ref = resolver.clone();
let domain_ref = domain.to_string(); // 如果必须的话,我们可以通过将cb_domain_iter放在Arc<>后面来消除这个.clone()
tokio::spawn(resolver_ref.lookup_ip(domain_ref))
});
for join in tasks {
join.await;
}
})
}
由于我.await
每个JoinHandle
,resolver
和cb_domain_iter
应该足够长以供tokio任务使用。然而,编译器并不知道这一点,如错误消息所示:
error[E0597]: `resolver_ref` does not live long enough
--> src/bin/test.rs:26:26
|
26 | tokio::spawn(resolver_ref.lookup_ip(domain_ref))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `resolver_ref` is borrowed for `'static`
27 | });
| - `resolver_ref` dropped here while still borrowed
这使我陷入了一些困境。从错误消息告诉我的来看,我理解创建的引用克隆在tokio spawn开始之前就被丢弃了,但是我很难使tokio任务同步地拥有引用。
也许有一些通过改变代码结构来强制其工作的方法,但我真的希望有一些像这里的.map(...)
提供的简单而功能性的东西。因此,理想情况下,解决方案将继续使用rust的函数式特性。
英文:
I am having convincing the compiler that certain variables live long enough.
Here is my code:
use trust_dns_resolver::{
config::{ResolverConfig, ResolverOpts},
TokioAsyncResolver,
};
fn main() {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(async {
let cb_domain_iter = vec!["example.com.", "google.com.", "facebook.com."];
let resolver = Arc::new(
TokioAsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default())
.expect("Could not create resolver"),
);
let tasks = cb_domain_iter.iter().map(move |domain| {
let resolver_ref = resolver.clone();
let domain_ref = domain.clone(); // we can get rid of this .clone() if we really have to by putting cb_domain_iter behind an Arc<>
tokio::spawn(resolver_ref.lookup_ip(domain_ref))
});
for join in tasks {
join.await;
}
})
}
Since I .await
each of the JoinHandle
s, the resolver
and cb_domain_iter
should live long enough for the tokio tasks. However, the compiler is unaware of this as seen in the error message:
error[E0597]: `resolver_ref` does not live long enough
--> src/bin/test.rs:26:26
|
26 | tokio::spawn(resolver_ref.lookup_ip(domain_ref))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `resolver_ref` is borrowed for `'static`
27 | });
| - `resolver_ref` dropped here while still borrowed
This brings me to a bit of a dillema. From what it tells me, I understand that the reference clone I create is dropped before the tokio spawn starts, but I am having trouble making the tokio task own the reference synchronously.
There may be ways to coerce this to work by changing the structure of the code, but I was really hoping for something simple & functional like what the .map(...)
is providing here. So ideally the solution continues to use the functional features of rust.
答案1
得分: 1
我认为解决方案是将resolver_ref
和domain_ref
简单地移到您传递给spawn
的未来中,而不是传递给它一些临时值:
tokio::spawn(async move { resolver_ref.lookup_ip(domain_ref).await })
英文:
I think the solution is to simply move resolver_ref
and domain_ref
into the future you give to spawn
instead of giving it some temporary:
tokio::spawn(async move {resolver_ref.lookup_ip(domain_ref).await })
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论