Search code examples
rustlifetimememory-safety

How do I set a static lifetime to a returned tuple in Rust?


Assume I have the following constructor that returns a tuple:

pub struct WebCam {
    id: u8
}

impl WebCam {
    fn new() -> (Self, bool) {
        let w = WebCam {id: 1 as u8};
        return (w, false);
    }
}

pub fn main() {
    static (cam, isRunning): (WebCam, bool) = WebCam::new();
}

The above code does not compile. However, if I change static to let it compiles just fine. I'm not sure how to set the lifetime on the individual values of the returned tuple (in one line)?


Solution

  • https://doc.rust-lang.org/reference/items/static-items.html

    It can be confusing whether or not you should use a constant item or a static item. Constants should, in general, be preferred over statics unless one of the following are true:

    Large amounts of data are being stored
    The single-address property of statics is required.
    Interior mutability is required.

    A static item is similar to a constant, except that it represents a precise memory location in the program. All references to the static refer to the same memory location. Static items have the static lifetime, which outlives all other lifetimes in a Rust program. Non-mut static items that contain a type that is not interior mutable may be placed in read-only memory. Static items do not call drop at the end of the program.

    All access to a static is safe, but there are a number of restrictions on statics:

    The type must have the Sync trait bound to allow thread-safe access. Statics allow using paths to statics in the constant expression used to initialize them, but statics may not refer to other statics by value, only through a reference. Constants cannot refer to statics.

    I would rewrite you code like this:

    pub struct WebCam {
        id: u8,
    }
    
    impl WebCam {
        fn new() -> (Self, bool) {
            (WebCam { id: 1u8 }, false)
        }
    }
    
    pub fn main() {
        let (cam, is_running) = WebCam::new();
        println!("{} {}", cam.id, is_running);
    }
    

    This works too:

    pub struct WebCam {
        id: u8,
    }
    
    impl WebCam {
        fn new() -> (Self, bool) {
            (WebCam { id: 1u8 }, false)
        }
    }
    static mut IS_RUNNING: bool = false;
    static mut WEB_CAM: WebCam = WebCam { id: 0u8 };
    
    pub fn main() {
        let (cam, is_running) = WebCam::new();
    
        unsafe {
            IS_RUNNING = is_running;
            WEB_CAM.id = cam.id;
        }
    
        println!("{} {}", cam.id, is_running);
    }