How to use lazy_static! inside a function?

Hi,

I'm trying to use lazy_static! inside a function as shown below.

fn check(line: String, search: &str) {
    lazy_static! {
        static ref REGEX: Regex = Regex::new(search).unwrap();
    }
    if REGEX.is_match(line.as_str()) { /****/ }
}

Resulting in this error

error[E0434]: can't capture dynamic environment in a fn item
 --> src/main.rs:9:46
  |
9 |         static ref REGEX: Regex = Regex::new(search).unwrap();
  |                                              ^^^^^^
  |
  = help: use the `|| { ... }` closure form instead

For more information about this error, try `rustc --explain E0434`.

The error is hinting to use a closure, but I can't make it work.

Any clue on how to proceed?

The lazy_static macro is meant to be used to generate static variables that are evaluated lazily.

Attempting to run it inside of a function is literally the complete opposite of what the macro is meant for.

1 Like

I was following the recommendation in regex crate
https://docs.rs/regex/latest/regex/#example-avoid-compiling-the-same-regex-in-a-loop
Here they're using lazy_static macro inside a helper function.

In that example they are not using the text parameter of the function in the initialiser of the lazy static. In your example you are using search in the initialiser. That isn't generally allowed for statics and it isn't clear why you want that, since it would make two consecutive calls to check() use the same regex, defeating the purpose of taking it as a function parameter in the first place.

1 Like

Be aware how there is no context from the helper function passed into the invocation of lazy_static!:

fn some_helper_function(text: &str) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new("...").unwrap();
    }
    RE.is_match(text)
}

I.e. The Regex matches anything that matches "..." (a &'static str known at compile time), not a dynamic regex pattern search (known only at runtime) as in your case. You can obviously create an instance of Regex at runtime, but without the lazy_static wrapper around it, as it is in fact dynamic and not static.

2 Likes

lazy_static! is meant for values that are known at compile time, but where there needs to be some runtime evaluation to get the final form. In the docs, they're using lazy_static! to make a hard-coded string into a Regex on first call to the function - which is different to your case, where you want a unique Regex per value of search.

The easiest route is to stop taking a str, and ask the caller to supply a Regex instead:

fn check(line: &str, search: &Regex) {
    if search.is_match(line) { /****/ }
}

If you absolutely need to take a string as search instead of a precompiled Regex and you can't afford the cost of compiling the string into a Regex on every call, then you're looking at building a cached memoization system, which can look up the right Regex each time you call it, and compile it if needed. This is not a small undertaking, and if it's something you need, then you'd be best served by searching crates.io for a caching crate that suits your needs already.

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.