借用的值在异步函数中存活时间不够长

3

我刚接触Rust,想要将一些代码变成异步的,以便并行运行多个任务。以下是一个简化的示例:

use futures::future::join_all;

#[tokio::main]
async fn main() {
    let mut list = Vec::new();
    for i in 1..10 {
        let my_str = format!("Value is: {:?}", &i);
        let future = do_something(&my_str);
        list.push(future);
    }
    join_all(list).await;
}

async fn do_something(value: &str)
{
    println!("value is: {:?}", value);
}

当调用do_something(&my_str)时,会出现“借用的值未能生存到足够长的时间”错误。通过将do_something更改为接受String而不是&str,我可以使代码编译。然而,要求使用String似乎有点奇怪,因为&str也可以工作。这里是否有更好的模式可用?谢谢!


1
顺便提一下,参见 https://tokio.rs/tokio/glossary#concurrency-and-parallelism 了解并发和并行的区别。Tokio 实现的是前者,而不是后者,在异步编程中,通常会实现并发,而不是并行。 - jthulhu
@BlackBeans 很好的观点 - 我正在编写的代码是I/O限制,但这里的简化示例不是。 - Daniel
1个回答

2

“然而,当一个&str可以工作时,要求一个字符串似乎有点奇怪。”但是在这里,&str不能工作,因为它只借用了my_str,而在未来完成之前就被销毁了:

for i in 1..10 {
    // Create a new `String` and store it in `my_str`
    let my_str = format!("Value is: {:?}", &i);
    // Create a future that borrows `my_str`. Note that the future is not
    // yet started
    let future = do_something(&my_str);
    // Store the future in `list`
    list.push(future);
    // Destroy `my_str` since it goes out of scope and wasn't moved.
}
// Run the futures from `list` until they complete. At this point each
// future will try to access the string that they have borrowed, but those
// strings have already been freed!
join_all(list).await;

相反,你的do_something函数应该负责管理字符串并释放它:

use futures::future::join_all;

#[tokio::main]
async fn main() {
    let mut list = Vec::new();
    for i in 1..10 {
        // Create a new `String` and store it in `my_str`
        let my_str = format!("Value is: {:?}", &i);
        // Create a future and _move_ `my_str` into it.
        let future = do_something(my_str);
        // Store the future in `list`
        list.push(future);
        // `my_str` is not destroyed since it was moved into the future.
    }
    join_all(list).await;
}

async fn do_something(value: String)
{
    println!("value is: {:?}", value);
    // Destroy `value` since it goes out of scope and wasn't moved.
}

1
谢谢,这真的很有帮助。我的理解是要避免在异步函数中接受 &str,因为它们可能会在参数超出作用域后执行。 - Daniel
如果do_something是一个无法更改的第三方函数,那该怎么办呢? - Saddle Point
2
@SaddlePoint 然后你只需将其包装在一个适应接口的 future 中,例如 let future = async move { do_something(&my_str).await }; - Jmb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接