Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I call a function that requires a 'static lifetime with a variable created in main?

Tags:

rust

lifetime

I've got a struct defined that has a function which defines a static lifetime:

impl MyStruct {
    pub fn doSomething(&'static self) {
        // Some code goes here
    }
}

I'm consuming it from main like so:

fn main() {
    let obj = MyStruct {};
    obj.doSomething();
}

It's intended for the doSomething call to block and execute for the lifetime of the application.

I'm running into issues with the lifetime checks where it's stating that it may outlive the main function, which seems strange to me as once main is complete the application should exit.

Is there a way to achieve this?

like image 519
lyptt Avatar asked Jun 07 '18 11:06

lyptt


People also ask

What is the lifetime of a static variable?

The space for the static variable is allocated only one time and this is used for the entirety of the program. Once this variable is declared, it exists till the program executes. So, the lifetime of a static variable is the lifetime of the program.

Can you declare a static variable in a function?

A static variable declaration is only executed once, the first time the function is executed. A static variable is initialized only once (since this is part of the declaration process) and will be initialized to 0 unless the programmer designates otherwise.

What is the lifetime and scope of static variable?

A static variable stays in the memory and retains its value until the program execution ends irrespective of its scope. Scope is of four types: file, block, function and prototype scope. Lifetime is of three types: static, auto and dynamic lifetime.

What does it mean for a variable inside of a function to be marked static?

In computer programming, a static variable is a variable that has been allocated "statically", meaning that its lifetime (or "extent") is the entire run of the program.


2 Answers

The primary way to create a reference that has the 'static lifetime is to make the variable static. A static variable is one that can be created at compile time:

struct MyStruct;

impl MyStruct {
    pub fn do_something(&'static self) {}
}

static OBJ: MyStruct = MyStruct;

fn main() {
    OBJ.do_something();
}

As Rust's constant evaluation story improves, this will be more common, but it will never allow configuration at runtime.

A far less common method is to deliberately leak memory, producing a reference that will last "forever". This should be discouraged because leaking memory isn't a good thing:

fn main() {
    let obj = Box::leak(Box::new(MyStruct));
    obj.do_something();
}

There's also the possibility of creating a singleton:

  • How do I create a global, mutable singleton?
  • How can you make a safe static singleton in Rust?

as once main is complete the application should exit.

Perhaps, but the compiler doesn't treat main specially for lifetime purposes.


hyper requires a static runtime when running the server and processing each request.

No, it doesn't. It has a bound of : 'static, which means that any references passed in must be 'static, but you don't have to pass in a bare reference at all.

For patterns like this, the most common thing is to pass in something like an Arc. This allows sharing of the underlying resource.

pub fn do_something<F, T>(f: F)
where
    F: Fn() -> T + 'static,
    T: 'static,
{
    // "spawn" 3 threads
    f();
    f();
    f();
}

struct MyStruct;

static OBJ: MyStruct = MyStruct;

fn main() {
    // OK
    do_something(|| &OBJ);

    // Not OK
    let another = MyStruct;
    do_something(|| &another);

    // OK
    use std::sync::Arc;
    let shared = Arc::new(MyStruct);
    do_something(move || shared.clone());
}

You can even use interior mutability if you wanted dynamic reconfiguration.

See also:

  • How do I use static lifetimes with threads?
like image 105
Shepmaster Avatar answered Oct 20 '22 10:10

Shepmaster


The naive way to do this is with a static variable, but it will require unsafe code if you need to actually set the value inside your main function:

static mut OBJ: MyStruct = MyStruct;

fn main() {
    unsafe {
        OBJ = MyStruct {};
        OBJ.doSomething();
    }
}

It's also unsafe to do pretty much anything with a mutable static thereafter.

The much better way to do it is to let a library (lazy_static) take care of the unsafe code.

use lazy_static::lazy_static;

fn main() {
    lazy_static!{
        static ref OBJ: MyStruct = MyStruct {};
    }
    OBJ.doSomething();
}
like image 37
Peter Hall Avatar answered Oct 20 '22 08:10

Peter Hall