Moka Cache Key Types Supported: Trait Bounds and Examples
Moka caches accept any key type implementing Hash + Eq + Send + Sync + 'static, and uniquely do not require Clone, enabling non-copyable structs and zero-cost abstractions.
The moka-rs/moka repository provides high-performance concurrent caching for Rust applications. Understanding which Moka cache key types are supported is essential for architecting efficient lookup structures, as the library places specific—but minimal—trait bounds on generic key parameters.
Core Trait Requirements for Moka Cache Keys
Moka’s Cache, SegmentedCache, and their async equivalents are generic over key type K with exactly four constraints. According to the moka-rs/moka source code, the core cache implementation in src/sync/cache.rs enforces K: Hash + Eq + Send + Sync + 'static on the generic impl for Cache<K, V, S> at lines 88-91.
The builder API applies identical constraints. In src/sync/builder.rs, lines 66-69, the CacheBuilder requires K: Eq + Hash + Send + Sync + 'static when constructing new cache instances.
These bounds ensure keys support:
- Hashing — For O(1) bucket lookups via the
Hashtrait - Equality comparison — For key matching via
Eq(which impliesPartialEq) - Thread safety — For concurrent access across threads via
Send + Sync - Static lifetime — For owned data safe to share without borrowing via
'static
Clone Is Not Required
Unlike standard Rust collections such as HashMap, Moka explicitly does not require keys to implement Clone. This architectural decision supports non-copyable types and eliminates unnecessary memory overhead when storing large or opaque keys.
The repository contains compile-time tests verifying this behavior. In tests/compile_tests/default/clone/sync_cache_clone.rs (lines 18-22) and tests/compile_tests/future/clone/future_cache_clone.rs (lines 19-23), the test suite confirms that custom structs lacking Clone compile successfully as cache keys.
Practical Examples of Supported Key Types
The following examples demonstrate valid key patterns for moka::sync::Cache and moka::future::Cache.
Primitive Types
Standard primitives like i32, u64, and String satisfy all trait bounds automatically.
use moka::sync::Cache;
let cache: Cache<i32, String> = Cache::new(100);
cache.insert(1, "one".to_string());
assert_eq!(cache.get(&1), Some("one".to_string()));
Custom Structs Without Clone
Define Hash and Eq manually or via derive macros. The example below uses a struct that explicitly does not implement Clone, matching the compile-test pattern from tests/compile_tests/default/clone/sync_cache_clone.rs.
use std::hash::{Hash, Hasher};
use moka::sync::Cache;
#[derive(Eq)]
struct MyKey(i32);
impl PartialEq for MyKey {
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
impl Hash for MyKey {
fn hash<H: Hasher>(&self, state: &mut H) { self.0.hash(state); }
}
// Note: MyKey does NOT implement Clone
let cache: Cache<MyKey, String> = Cache::new(10);
cache.insert(MyKey(42), "answer".to_string());
assert_eq!(cache.get(&MyKey(42)), Some("answer".to_string()));
Reference-Counted Wrappers
Types like Arc<T> work efficiently as keys when T implements the required traits, enabling shared ownership patterns without cloning underlying data.
Custom Hashers
Supply a custom BuildHasher implementation via the builder API when specific hashing algorithms are required. The key type constraints remain unchanged regardless of hasher selection.
use moka::sync::Cache;
use ahash::RandomState;
let hasher = RandomState::new();
let cache: Cache<u64, String, _> = Cache::builder()
.max_capacity(50)
.build_with_hasher(hasher);
cache.insert(7, "seven".to_string());
assert_eq!(cache.get(&7), Some("seven".to_string()));
Async Cache Compatibility
The async cache implementations mirror the sync requirements exactly. In src/future/cache.rs and src/future/builder.rs, the future::Cache and future::CacheBuilder enforce identical K: Hash + Eq + Send + Sync + 'static bounds. This parity ensures key types are portable between synchronous and asynchronous cache variants without modification.
Summary
- Moka cache key types must implement
Hash + Eq + Send + Sync + 'staticas defined insrc/sync/cache.rsandsrc/sync/builder.rs - The
Clonetrait is not required, verified by compile-time tests intests/compile_tests/*/clone/*.rs - Primitive types, custom structs, and
Arc<T>wrappers are all valid key candidates - Async caches (
future::Cache) apply identical trait constraints to their synchronous counterparts - Custom hashers can be specified without altering key type requirements
Frequently Asked Questions
Do Moka cache keys need to implement Clone?
No. Moka explicitly designs against requiring Clone for keys. The source code includes compile-time tests in tests/compile_tests/default/clone/sync_cache_clone.rs and tests/compile_tests/future/clone/future_cache_clone.rs that verify non-cloneable structs work correctly as cache keys.
Can I use String as a key in Moka?
Yes. String implements Hash, Eq, Send, Sync, and 'static, making it a fully supported key type without additional configuration or wrapper types.
What hash algorithm does Moka use by default?
Moka uses std::collections::hash_map::RandomState (SipHash) by default for DOS resistance. You can override this with any BuildHasher implementation, such as ahash::RandomState, via Cache::builder().build_with_hasher() while maintaining the same key type constraints.
Are tuples supported as Moka cache keys?
Yes. Tuples containing types that implement Hash and Eq (such as (i32, String) or (u64, u64)) automatically implement these traits themselves and are valid Moka cache key types.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →