ExamplesBy LevelBy TopicLearning Paths
536 Intermediate

'static Lifetime

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "'static Lifetime" functional Rust example. Difficulty level: Intermediate. Key concepts covered: Functional Programming. `'static` is the longest possible lifetime in Rust — it means "valid for the entire program duration." String literals embedded in the binary are `'static str`. Key difference from OCaml: 1. **Binary embedding**: Rust `&'static str` literals are embedded in the binary's read

Tutorial

The Problem

'static is the longest possible lifetime in Rust — it means "valid for the entire program duration." String literals embedded in the binary are 'static str. Global constants and statics are 'static. The 'static bound on trait objects (Box<dyn Trait + 'static>) means the type contains no non-static references — it can be sent across thread boundaries and stored in long-lived data structures. Understanding 'static is essential for thread-safe data sharing, global configuration, error type design, and trait object storage.

🎯 Learning Outcomes

  • • What 'static means: the reference is valid for the entire program's lifetime
  • • How string literals ("hello") are &'static str — embedded in the binary
  • • How owned types (String, Vec<T>) satisfy 'static bounds because they have no borrows
  • • How 'static bounds on trait objects (Box<dyn Error + 'static>) enable thread-safe error handling
  • • Where 'static is required: thread::spawn, global statics, Box<dyn Any + 'static>
  • Code Example

    // 'static means "valid for entire program duration"
    pub static APP_NAME: &'static str = "MyRustApp";
    
    // String literals are automatically &'static str
    pub fn get_greeting() -> &'static str {
        "Hello, World!"  // embedded in binary
    }
    
    // Thread spawn requires 'static (outlive caller)
    std::thread::spawn(move || { /* 'static data only */ });

    Key Differences

  • Binary embedding: Rust &'static str literals are embedded in the binary's read-only data segment; OCaml string literals are GC-allocated heap objects (though the compiler may intern them).
  • Thread safety: Rust 'static bound on thread::spawn's closure ensures no borrowed references cross the thread boundary; OCaml's GC manages cross-thread safety through domain locks in OCaml 5.x.
  • Owned data and 'static: In Rust, String: 'static because it has no borrows — a subtle but important distinction between "is 'static data" and "satisfies 'static bound"; OCaml has no equivalent.
  • Error types: Rust Box<dyn std::error::Error + 'static> is the standard owned error type; OCaml exceptions are values of type exn with no lifetime tracking.
  • OCaml Approach

    OCaml has no 'static concept. All values are GC-managed and valid as long as any reference exists. Global values are declared with let at module scope:

    let app_name = "MyApp"            (* module-level, available everywhere *)
    let error_messages = [(404, "Not Found"); (500, "Internal Server Error")]
    

    The GC ensures these are always valid — there is no concept of a lifetime expiring.

    Full Source

    #![allow(clippy::all)]
    //! 'static Lifetime
    //!
    //! Program-duration references: literals, statics, and 'static bounds.
    
    /// String literals are &'static str — embedded in binary.
    pub static APP_NAME: &str = "MyRustApp";
    pub static VERSION: &str = "1.0.0";
    pub static MAX_CONNECTIONS: usize = 100;
    
    /// Static slice.
    pub static ERROR_MESSAGES: &[(u16, &str)] = &[
        (404, "Not Found"),
        (500, "Internal Server Error"),
        (403, "Forbidden"),
        (200, "OK"),
    ];
    
    pub fn get_error_msg(code: u16) -> &'static str {
        ERROR_MESSAGES
            .iter()
            .find(|&&(c, _)| c == code)
            .map(|(_, msg)| *msg)
            .unwrap_or("Unknown Error")
    }
    
    /// Return a string literal — always 'static.
    pub fn get_greeting() -> &'static str {
        "Hello, World!"
    }
    
    /// Owned data can satisfy 'static bound.
    pub fn make_static_string() -> String {
        // String is 'static because it owns its data (no borrows)
        String::from("I am owned")
    }
    
    /// Function accepting 'static data.
    pub fn store_static(s: &'static str) -> &'static str {
        s
    }
    
    /// Thread spawn requires 'static (data must outlive thread).
    pub fn spawn_example() {
        let owned = String::from("owned data");
        // std::thread::spawn requires 'static
        // move closure transfers ownership
        let _handle = std::thread::spawn(move || {
            println!("{}", owned);
        });
    }
    
    /// 'static bound on generic: T must not contain non-static borrows.
    pub fn needs_static<T: 'static>(value: T) -> T {
        value
    }
    
    /// Lazy static pattern (without lazy_static crate).
    use std::sync::OnceLock;
    
    static CONFIG: OnceLock<String> = OnceLock::new();
    
    pub fn get_config() -> &'static str {
        CONFIG.get_or_init(|| String::from("default_config"))
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_static_str() {
            let s: &'static str = "literal";
            assert_eq!(s, "literal");
        }
    
        #[test]
        fn test_static_constants() {
            assert_eq!(APP_NAME, "MyRustApp");
            assert_eq!(VERSION, "1.0.0");
        }
    
        #[test]
        fn test_get_error_msg() {
            assert_eq!(get_error_msg(404), "Not Found");
            assert_eq!(get_error_msg(999), "Unknown Error");
        }
    
        #[test]
        fn test_get_greeting() {
            let greeting: &'static str = get_greeting();
            assert_eq!(greeting, "Hello, World!");
        }
    
        #[test]
        fn test_needs_static_owned() {
            // String satisfies 'static because it owns its data
            let s = needs_static(String::from("hello"));
            assert_eq!(s, "hello");
        }
    
        #[test]
        fn test_needs_static_literal() {
            // &'static str satisfies 'static
            let s = needs_static("literal");
            assert_eq!(s, "literal");
        }
    
        #[test]
        fn test_get_config() {
            let config = get_config();
            assert_eq!(config, "default_config");
        }
    
        #[test]
        fn test_store_static() {
            let result = store_static("hello");
            assert_eq!(result, "hello");
        }
    }
    ✓ Tests Rust test suite
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_static_str() {
            let s: &'static str = "literal";
            assert_eq!(s, "literal");
        }
    
        #[test]
        fn test_static_constants() {
            assert_eq!(APP_NAME, "MyRustApp");
            assert_eq!(VERSION, "1.0.0");
        }
    
        #[test]
        fn test_get_error_msg() {
            assert_eq!(get_error_msg(404), "Not Found");
            assert_eq!(get_error_msg(999), "Unknown Error");
        }
    
        #[test]
        fn test_get_greeting() {
            let greeting: &'static str = get_greeting();
            assert_eq!(greeting, "Hello, World!");
        }
    
        #[test]
        fn test_needs_static_owned() {
            // String satisfies 'static because it owns its data
            let s = needs_static(String::from("hello"));
            assert_eq!(s, "hello");
        }
    
        #[test]
        fn test_needs_static_literal() {
            // &'static str satisfies 'static
            let s = needs_static("literal");
            assert_eq!(s, "literal");
        }
    
        #[test]
        fn test_get_config() {
            let config = get_config();
            assert_eq!(config, "default_config");
        }
    
        #[test]
        fn test_store_static() {
            let result = store_static("hello");
            assert_eq!(result, "hello");
        }
    }

    Deep Comparison

    OCaml vs Rust: 'static Lifetime

    OCaml

    (* No concept of 'static — all values managed by GC *)
    let app_name = "MyRustApp"  (* string literal, GC-managed *)
    
    let error_messages = [
      (404, "Not Found");
      (500, "Internal Server Error")
    ]
    

    Rust

    // 'static means "valid for entire program duration"
    pub static APP_NAME: &'static str = "MyRustApp";
    
    // String literals are automatically &'static str
    pub fn get_greeting() -> &'static str {
        "Hello, World!"  // embedded in binary
    }
    
    // Thread spawn requires 'static (outlive caller)
    std::thread::spawn(move || { /* 'static data only */ });
    

    Key Differences

  • OCaml: GC handles all lifetimes uniformly
  • Rust: 'static means "lives forever" (program duration)
  • Rust: String literals are &'static str (in binary)
  • Rust: Owned types satisfy 'static bound
  • Rust: Thread safety often requires 'static
  • Exercises

  • Static dispatch table: Define a static OPS: &[(&str, fn(i32) -> i32)] at module level mapping names to operations, and write a lookup function returning Option<fn(i32) -> i32>.
  • 'static bound function: Write fn store_in_vec<T: 'static>(v: &mut Vec<Box<dyn std::any::Any>>, item: T) and verify it rejects types with non-static borrows.
  • Lazy static config: Use std::sync::OnceLock<&'static str> to store a program-global greeting initialized from a command-line argument on first access.
  • Open Source Repos