Open denizs opened 6 years ago
I just ran into this problem as well. I would like to do the following:
fn initialize(options: Options, window: Window) {
lazy_static! {
static ref STATE: State = State::new(options, window);
}
...
}
However I get this error:
error[E0434]: can't capture dynamic environment in a fn item
--> src\bin\sidebar\main.rs:1386:46
|
1386 | static ref STATE: State = State::new(options, window);
| ^^^^^^^
|
= help: use the `|| { ... }` closure form instead
There are some complex reasons for why I need to use lazy_static
(I can't just use a state
local variable).
I tried to implement this, and as far as I can tell it's currently impossible, due to static
restrictions in Rust.
I wouldn't say this is static
restrictions -- you will first need to figure out what stops someone from writing code like the following. After you conceptually understand what the behavior should be in such cases, it will be clearer how to proceed in implementing that behavior.
#[macro_use]
extern crate lazy_static;
fn initialize(options: Options, window: Window) -> &'static impl Deref<Target = State> {
lazy_static! {
static ref STATE: State = State::new(options, window);
}
&STATE
}
fn main() {
let state = initialize(...);
// Dereference STATE for the very first time, lazily initializing
// it. But oops, by now `options` and `window` have been destroyed
// so this is a use-after-free.
println!("{:?}", **state);
}
@dtolnay That particular issue isn't a problem, since the implementation I created uses a move
closure to capture the outer variables.
The real issue is that it's not possible to put closures into static
(which is why I said that the current static
restrictions prevent this).
It's possible but unstable:
#![feature(existential_type, untagged_unions)]
#[macro_use]
extern crate lazy_static;
#[derive(Debug)]
struct Options(i32);
#[derive(Debug)]
struct Window(i32);
#[derive(Debug)]
struct State(Options, Window);
impl State {
fn new(options: Options, window: Window) -> Self {
State(options, window)
}
}
existential type Init: FnOnce() -> State;
fn initialize(options: Options, window: Window) {
#[allow(unions_with_drop_fields)]
union BrieflyUninit {
uninit: (),
value: Init,
}
static mut INIT: BrieflyUninit = BrieflyUninit { uninit: () };
let init = move || -> Init { move || State::new(options, window) };
unsafe {
std::ptr::write(&mut INIT.value, init());
}
lazy_static! {
static ref STATE: State = unsafe { std::ptr::read(&INIT.value)() };
}
println!("{:?}", *STATE);
}
fn main() {
initialize(Options(1), Window(2));
}
Hey there, I was just wondering, whether there was a way to declare a static ref based on a variable outside the macro. More specifically, something along the lines of
Thanks in advance!