Can we have lazy type like this:
fn foo(a1 : int, a2 : !int) -> !int {
}
where ! denote lazy
Could you please elaborate? I’m not sure what you mean to achieve. (Note: I only know c# has lazy types, not what they are or how they work)
Do you mean something like this:
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::thunk::Invoke;
enum LazyInner<'a, T> {
Uninitialized(Option<Box<Invoke<(), T> + 'a>>),
Initialized(T),
}
pub struct Lazy<'a, T> {
inner: UnsafeCell<LazyInner<'a, T>>,
}
impl<'a, T> Lazy<'a, T> {
pub fn new<F: 'a>(f: F) -> Self where F: FnOnce() -> T {
Lazy {
inner: UnsafeCell::new(LazyInner::Uninitialized(Some(Box::new(move |()|f()))))
}
}
}
impl<'a, T> Deref for Lazy<'a, T> {
type Target = T;
fn deref(&self) -> &T {
use LazyInner::*;
unsafe {
match *self.inner.get() {
Uninitialized(ref mut f) => match f.take() {
Some(f) => {
*self.inner.get() = Initialized(f.invoke(()));
&self
},
None => unreachable!(),
},
Initialized(ref value) => value,
}
}
}
}
impl<'a, T> DerefMut for Lazy<'a, T> {
fn deref_mut(&mut self) -> &mut T {
use LazyInner::*;
unsafe {
match *self.inner.get() {
Uninitialized(ref mut f) => match f.take() {
Some(f) => {
*self.inner.get() = Initialized(f.invoke(()));
&mut *self
},
None => unreachable!(),
},
Initialized(ref mut value) => value,
}
}
}
}
macro_rules! lazy {
($($s:stmt);+) => {{
Lazy::new(|| { $($s);+ })
}};
}
macro_rules! movable_lazy {
($($s:stmt);+) => {{
Lazy::new(move || { $($s);+ })
}};
}
fn test(value: &Lazy<u8>) {
println!("{}", **value);
}
fn main() {
let l = lazy! {
println!("computing");
1u8 + 2 + 3 + 4
};
test(&l);
test(&l);
}
I doubt this functionality will ever be included in rust itself because it’s a very high level concept and is not a zero-cost abstraction but those macros work fairly well (but could clearly be improved/optimized).
I rarely need lazy values in practice. When I have, FnMut() -> T
has been
enough, although granted, passing closures around is a little more
heavyweight than I’d like it to be (adding a closure means coming up with a
name, adding a type parameter, adding a constraint, and then finally adding
the value parameter). Other than that, though, I don’t really see a
motivation to add more sugar?
There is a lazy library already that provides very close to what you are looking for, https://github.com/reem/rust-lazy.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.