Course contentsShow
← Rust
Lesson 380 of 1,9104. Lifetimes and Advanced OwnershipFree lesson

Caching Results with Borrowed Keys

Implement look-up tables that maintain references to keys for high-performance retrieval.

In this lesson, you will learn how to design high-performance cache structures that store references to existing keys instead of forcing expensive data duplication.

The Problem: Ownership Overhead

When building a cache (like a HashMap), it is tempting to store owned types like String as keys. However, if your application already holds that String in a long-lived configuration or data store, cloning it just to put it into a cache wastes memory and CPU cycles. Ideally, we want the cache to store references (&str) to the original data.

The Solution: Borrowed Keys

To implement a cache that holds borrowed keys, your struct must explicitly account for the lifetime of those keys. This is where Lifetime Bounds on Structs (Concept #3) become essential.

Consider this lookup table designed to cache results based on existing &str keys:

use std::collections::HashMap;

struct ResultCache<'a> {
    // The cache holds references, so we need a lifetime 'a
    // The key is a reference, and the value is the computed result
    data: HashMap<&'a str, i32>,
}

impl<'a> ResultCache<'a> {
    fn get_or_insert(&mut self, key: &'a str, value: i32) -> i32 {
        *self.data.entry(key).or_insert(value)
    }
}

Why This Matters

By using &'a str, we ensure the ResultCache cannot outlive the strings it points to. If you tried to pass a temporary string into this cache, the compiler would trigger a lifetime error, preventing a dangling pointer. This pattern allows for high-performance retrieval because lookups only compare references (or hashes of those references) rather than copying large chunks of heap-allocated memory.

This approach is highly effective in scenarios where you have a "Source of Truth" (like a pool of static configuration strings or a master data buffer) and need to perform frequent, repeated lookups without the cost of memory allocation. You are essentially creating a view into your data that acts as a fast-lookup index.

Key Takeaway: By using generic lifetime parameters in your cache struct, you can store borrowed keys to perform high-performance lookups without the memory overhead of duplicating your source data.