3 ms·
That can still be done without a GC, e.g. the following is sketch of lazy evaluation in Rust: use std::mem; enum Lazy<T> { Thunk(Box<Fn() -> T>),
by dbaupp 11y ago
That can still be done without a GC, e.g. the following is sketch of lazy evaluation in Rust:
use std::mem;
enum Lazy<T> {
Thunk(Box<Fn() -> T>),
EvalInProgress,
Forced(T),
}
impl<T> Lazy<T> {
fn new<F: 'static + Fn() -> T>(f: F) -> Lazy<T> {
Lazy::Thunk(Box::new(f))
}
fn force(&mut self) {
*self = match mem::replace(self, Lazy::EvalInProgress) {
Lazy::Thunk(f) => Lazy::Forced(f()),
Lazy::EvalInProgress => panic!("forcing while evaluating"),
Lazy::Forced(x) => Lazy::Forced(x),
}
}
fn get(&mut self) -> &mut T {
self.force();
match *self {
Lazy::Thunk(_) | Lazy::EvalInProgress => unreachable!(),
Lazy::Forced(ref mut x) => x,
}
}
}
fn main() {
let mut lazy = Lazy::new(|| {
println!("evaluating");
10
});
println!("first: {}", lazy.get());
println!("second: {}", lazy.get());
}
Output:
evaluating
first: 10
second: 10
(There's a pile of tweaks/optimisations that can be made, like making `force` truly a no-op for values that have already been forced and removing the need for the lazy object to be mutable, but the above demonstrates the core idea.)