The purpose of lazy is covered by the documentation for lazy
:
Creates a new future which will eventually be the same as the one created by the closure provided.
The provided closure is only run once the future has a callback scheduled on it, otherwise the callback never runs. Once run, however, this future is the same as the one the closure creates.
Like a plain closure, it's used to prevent code from being eagerly evaluated. In synchronous terms, it's the difference between calling a function and calling the closure that the function returned:
fn sync() -> impl FnOnce() {
println!("This is run when the function is called");
|| println!("This is run when the return value is called")
}
fn main() {
let a = sync();
println!("Called the function");
a();
}
And the parallel for futures 0.1:
use futures::{future, Future}; // 0.1.27
fn not_sync() -> impl Future<Item = (), Error = ()> {
println!("This is run when the function is called");
future::lazy(|| {
println!("This is run when the return value is called");
Ok(())
})
}
fn main() {
let a = not_sync();
println!("Called the function");
a.wait().unwrap();
}
With async
/await
syntax, this function should not be needed anymore:
#![feature(async_await)] // 1.37.0-nightly (2019-06-05)
use futures::executor; // 0.3.0-alpha.16
use std::future::Future;
fn not_sync() -> impl Future<Output = ()> {
println!("This is run when the function is called");
async {
println!("This is run when the return value is called");
}
}
fn main() {
let a = not_sync();
println!("Called the function");
executor::block_on(a);
}
As you've identified, Tokio's examples use lazy
to:
- ensure that the code in the closure is only run from inside the executor.
- ensure that a closure is run as a future
I view these two aspects of lazy
as effectively the same.
See also: