I am trying to write a cache struct in rust.
use std::collections::hash_map::{self, DefaultHasher};
use std::hash::{self, Hasher};
use std::time::SystemTime;
// use hash values in a hashmap to prevent deep copy of keys
type KeyHash = u64;
pub struct WeightedCache<V> {
map: hash_map::HashMap<KeyHash, (V, f64)>,
last_access_time: hash_map::HashMap<KeyHash, SystemTime>,
dirty_access_time: Vec<(KeyHash, SystemTime)>,
max_capacity: i32,
current_capacity: i32,
}
pub trait Cache<K, V> {
fn new(max_capacity: i32) -> Self;
fn get(&mut self, key: K) -> &V;
fn put(&mut self, key: K, value: V, weight: f64);
fn _calc_score(&self, hash_val: KeyHash) -> f64;
fn _evict_one(&self);
fn _hash(&self, key: &K) -> KeyHash;
}
impl<K, V> Cache<K, V> for WeightedCache<V> {
fn new(max_capacity: i32) -> WeightedCache<V> {
...
}
fn _hash(&self, key: &K) -> KeyHash {
...
}
fn _calc_score(&self, hash_val: KeyHash) -> f64 {
...
}
fn _evict_one(&self) {
assert!(self.current_capacity == self.max_capacity);
let mut min_score = f64::MAX;
let mut evict: Option<KeyHash> = None;
for hash_key in self.map.keys() {
let score: f64 = self._calc_score(*hash_key as KeyHash); //this line has an error
if score < min_score {
min_score = score;
evict = Some(*hash_key);
}
}
self.map.remove(&evict.unwrap());
self.last_access_time.remove(&evict.unwrap());
}
fn get(&mut self, key: K) -> &V {
...
}
fn put(&mut self, key: K, value: V, weight: f64) {
...
}
}
But there is an error at the line : self._calc_score(*hash_key as KeyHash) in fn _evict_one(&self)
The compiler shows:
error[E0282]: type annotations needed
--> src/main.rs:63:35
|
63 | let score: f64 = self._calc_score(*hash_key as KeyHash);
| ^^^^^^^^^^^
|
help: try using a fully qualified path to specify the expected types
|
63 | let score: f64 = <WeightedCache<V> as Cache<K, V>>::_calc_score(self, *hash_key as KeyHash);
| +++++++++++++++++++++++++++++++++++++++++++++++ ~
When replace the line with what the compiler recommended, it works. Can someone help me explain why?
Is there a way to get away with it without using a long line of code e.g. can i use the same self._calc_score as before?
WeightedCache<V>implementsCache<K, V>for every key typeKso the compiler can't figure out which one of them to pick. Neither the typeWeightetCache<V>nor the signature of_calc_score(&self, KeyHash)limit's it to a single implementation.So instead of
you might want to call
or
and there's just no way for the compiler to tell which one to pick without you helping it.
You can use:
instead, which is a little shorter and does not contain redundant information.
Alternatively you could split your traits into methods that do and don't use
K. ThenCache::_calc_scoreis unambiguous and you can use the method call syntax:But that might not be feasible depending on how exactly your methods interact.