'static Lifetime
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
'static means: the reference is valid for the entire program's lifetime"hello") are &'static str — embedded in the binaryString, Vec<T>) satisfy 'static bounds because they have no borrows'static bounds on trait objects (Box<dyn Error + 'static>) enable thread-safe error handling'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
&'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).'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.String: 'static because it has no borrows — a subtle but important distinction between "is 'static data" and "satisfies 'static bound"; OCaml has no equivalent.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");
}
}#[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
Exercises
static OPS: &[(&str, fn(i32) -> i32)] at module level mapping names to operations, and write a lookup function returning Option<fn(i32) -> i32>.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.std::sync::OnceLock<&'static str> to store a program-global greeting initialized from a command-line argument on first access.