英文:
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 JoinHandles, 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 })
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论