// Example 107: Lifetimes in Structs
//
// When a struct holds a reference, it needs a lifetime parameter
// to ensure the referenced data outlives the struct.
// Approach 1: Struct borrowing a string slice
#[derive(Debug)]
struct Excerpt<'a> {
text: &'a str,
page: u32,
}
fn approach1() {
let book = String::from("Call me Ishmael. Some years ago...");
let exc = Excerpt { text: &book[..16], page: 1 };
assert_eq!(exc.text, "Call me Ishmael.");
println!("Excerpt p.{}: {}", exc.page, exc.text);
// exc cannot outlive book
}
// Approach 2: Struct with multiple borrowed fields
#[derive(Debug)]
struct Article<'a> {
title: &'a str,
author: &'a str,
body: &'a str,
}
impl<'a> Article<'a> {
fn summarize(&self) -> String {
format!("{} by {} ({} chars)", self.title, self.author, self.body.len())
}
}
fn approach2() {
let title = String::from("Rust Ownership");
let author = String::from("Alice");
let body = String::from("Ownership is...");
let a = Article { title: &title, author: &author, body: &body };
println!("{}", a.summarize());
}
// Approach 3: Nested structs with lifetimes
#[derive(Debug)]
struct Highlight<'a> {
excerpt: Excerpt<'a>,
note: &'a str,
}
fn approach3() {
let text = String::from("important passage");
let note = String::from("Remember this!");
let exc = Excerpt { text: &text, page: 42 };
let h = Highlight { excerpt: exc, note: ¬e };
assert_eq!(h.excerpt.page, 42);
println!("Highlight p.{}: {} โ {}", h.excerpt.page, h.excerpt.text, h.note);
}
fn main() {
println!("=== Approach 1: Basic Struct with Lifetime ===");
approach1();
println!("\n=== Approach 2: Multiple Borrowed Fields ===");
approach2();
println!("\n=== Approach 3: Nested Lifetimes ===");
approach3();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_excerpt() {
let text = "hello world";
let e = Excerpt { text, page: 1 };
assert_eq!(e.text, "hello world");
}
#[test]
fn test_article_summarize() {
let a = Article { title: "T", author: "A", body: "12345" };
assert!(a.summarize().contains("5 chars"));
}
#[test]
fn test_highlight() {
let e = Excerpt { text: "test", page: 1 };
let h = Highlight { excerpt: e, note: "note" };
assert_eq!(h.note, "note");
}
#[test]
fn test_lifetime_scope() {
let outer = String::from("outer");
let e = Excerpt { text: &outer, page: 1 };
assert_eq!(e.text, "outer");
// e cannot outlive outer โ compiler enforces this
}
}
(* Example 107: Lifetimes in Structs โ Storing References Safely *)
(* Approach 1: Struct holding a reference to external data *)
type excerpt = { text : string; page : int }
let make_excerpt text page = { text; page }
let approach1 () =
let book = "Call me Ishmael. Some years ago..." in
let exc = make_excerpt (String.sub book 0 16) 1 in
assert (exc.text = "Call me Ishmael.");
Printf.printf "Excerpt p.%d: %s\n" exc.page exc.text
(* Approach 2: Struct with multiple string fields *)
type article = { title : string; author : string; body : string }
let summarize a =
Printf.sprintf "%s by %s (%d chars)" a.title a.author (String.length a.body)
let approach2 () =
let a = { title = "Rust Ownership"; author = "Alice"; body = "Ownership is..." } in
let s = summarize a in
Printf.printf "%s\n" s
(* Approach 3: Nested structs with shared data *)
type highlight = { excerpt : excerpt; note : string }
let approach3 () =
let exc = { text = "important passage"; page = 42 } in
let h = { excerpt = exc; note = "Remember this!" } in
assert (h.excerpt.page = 42);
Printf.printf "Highlight p.%d: %s โ %s\n" h.excerpt.page h.excerpt.text h.note
let () =
approach1 ();
approach2 ();
approach3 ();
Printf.printf "โ All tests passed\n"