In some cases it would be useful for a struct/object to be able to start some tasks and then allow struct users to stop these tasks and await for result. I could of course send result with channel or shared resource but using return value would be cleaner in many cases. Also I understand from experience in other async languages that it is good practice to always await your tasks at some point in code.
I cannot make the borrow checker to accept the following attempt to implement the idea over. Can someone explain it? and even better can I find a way out of it?
use tokio::time;
use tokio::task::JoinError;
struct S {
pub task: tokio::task::JoinHandle<bool>,
}
impl S {
pub async fn new() -> Self {
let task = tokio::task::spawn(async {
time::sleep(time::Duration::from_secs(10)).await;
true
});
Self { task }
}
pub async fn join_and_get_result(&self) -> Result<bool, JoinError> {
self.task.await // cannot move out of `self.task` which is behind a shared reference
}
}
#[tokio::main]
async fn main() {
let s = S::new().await;
s.join_and_get_result().await;
let result = s.task.await; // this is fine for borrow checker but requires to expose internal implementation
}
>Solution :
Calling .await on a task consumes the task. You can fix the error by making join_and_get_result take self and not &self, which will move S into the function making it possible to call .await on the task:
use tokio::task::JoinError;
use tokio::time;
struct S {
pub task: tokio::task::JoinHandle<bool>,
}
impl S {
pub async fn new() -> Self {
let task = tokio::task::spawn(async {
time::sleep(time::Duration::from_secs(10)).await;
true
});
Self { task }
}
pub async fn join_and_get_result(self) -> Result<bool, JoinError> {
self.task.await
}
}
#[tokio::main]
async fn main() {
let s = S::new().await;
let result = s.join_and_get_result();
}