Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy evaluation in Rust

I am a Rust noob with extensive Java experience.

There is code that runs through some logic and eventually comes up with the status of those calculations, captured in Report (see below). The Report is only used under certain circumstances, so I don't need its contents (just a String) to be evaluated if it is not necessary, so I use LazyCell.

use std::cell::LazyCell;
use std::error::Error;
use std::fmt;
use std::fmt::Display;
use std::fmt::Formatter;

pub struct Report {
    msg: LazyCell<String>,
}

impl Report {
    pub fn from_err(err: impl Display) -> Self {
        Report { msg: LazyCell::new(|| { err.to_string() }) }
    }
    pub fn from_str(str: String) -> Self {
        Report { msg: LazyCell::new(|| { str }) }
    }
}

impl Display for Report {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "SimpleError: {}", *self.msg)
    }
}

Obviously it doesn't compile complaining "closures can only be coerced to `fn` types if they do not capture any variables". My intent is to simply keep err and only extract its string form if/when needed.

I suspect I'm not approaching it "the Rust way" in which case I need to get out of my boxed vision of this, but my Rust field of view is still limited

like image 869
oᴉɹǝɥɔ Avatar asked Sep 17 '25 23:09

oᴉɹǝɥɔ


1 Answers

LazyCell actually takes two generic parameters: the first is of course the type of the data, but the second is the type of the callback. It is defaulted to fn() -> Data to assist with the common case (especially with LazyLock) of lazily-initializing a static, but in your case you can specify it as Box<dyn FnOnce() -> String>:

use std::cell::LazyCell;
use std::fmt;
use std::fmt::Display;
use std::fmt::Formatter;

pub struct Report {
    msg: LazyCell<String, Box<dyn FnOnce() -> String>>,
}

impl Report {
    pub fn from_err(err: impl Display + 'static) -> Self {
        Report {
            msg: LazyCell::new(Box::new(move || err.to_string())),
        }
    }
    pub fn from_str(str: String) -> Self {
        Report {
            msg: LazyCell::new(Box::new(move || str)),
        }
    }
}

impl Display for Report {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "SimpleError: {}", *self.msg)
    }
}
like image 123
Chayim Friedman Avatar answered Sep 19 '25 17:09

Chayim Friedman