Memoize when key does not implement Clone trait - rust

In the below lazy memoization example, how do I return the memoized value when the key does not implement the Clone trait?
In below implementation, as the value of key is already moved, how can we query the value from the store again with the given key?
Is there a better way to write this code when key does not implement the clone trait?
struct Cacher<T, Y>
where
T: Fn(&Y) -> Y,
Y: Eq + Hash,
{
store: HashMap<Y, Y>,
compute: T,
}
impl<T, Y> Cacher<T, Y>
where
T: Fn(&Y) -> Y,
Y: Eq + Hash,
{
fn new(comp: T) -> Self {
Cacher {
compute: comp,
store: HashMap::new(),
}
}
fn get(&mut self, key: Y) -> Option<&Y> {
if self.store.contains_key(&key) {
self.store.get(&key)
} else {
let value = (self.compute)(&key);
self.store.insert(key, value);
self.store.get(&key) //<---- This is problematic
}
}
}

Use the entry API:
fn get(&mut self, key: Y) -> &Y {
if self.store.contains_key(&key) {
self.store.get(&key).unwrap()
} else {
let value = (self.compute)(&key);
match self.store.entry(key) {
Entry::Occupied(entry) => unreachable!(),
Entry::Vacant(entry) => entry.insert(value)
}
}
}
However, at this point it is better (and more performant) to use the entry API solely:
fn get(&mut self, key: Y) -> &Y {
match self.store.entry(key) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
let value = (self.compute)(entry.key());
entry.insert(value)
}
}
}
Or with combinators:
fn get(&mut self, key: Y) -> &Y {
self.store.entry(key).or_insert_with_key(&self.compute)
}

Related

How to impl conversion between different inner types?

This yields E0119:
#![feature(destructuring_assignment)]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl<F, T: From<F>> From<Point<F>> for Point<T> {
fn from<F>(f: Point<F>) -> Self {
let Point { mut x, mut y } = f;
(x, y) = (T::from(x), T::from(y));
Self { x, y }
}
}
The implementation conflict is in std::convert::From for T:
impl<T> From<T> for T {
fn from(t: T) -> T {
t
}
}
I assume there isn't a way to work around this so much as there may be more rust-idiomatic approach to the problem of converting between inner types, or even a more idiomatic understanding of what the "problem" is.
You can implement it as a normal method that takes a closure and then pass it the From::from trait method when you call it. Or even specialize it for types that implement From<T>:
#[derive(Debug)]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl<T> Point<T> {
pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Point<U> {
let Point { x, y } = self;
Point {
x: f(x),
y: f(y),
}
}
pub fn map_into<U: From<T>>(self) -> Point<U> {
let Point { x, y } = self;
Point {
x: U::from(x),
y: U::from(y),
}
}
}
fn main() {
let point_i16 = Point { x: 6i16, y: 3200i16 };
let point_f32: Point<f32> = point_i16.map(From::from);
let point_f64: Point<f64> = point_f32.map_into();
println!("{:?}", point_f64); // Point { x: 6.0, y: 3200.0 }
}

Cannot modify the field in recursive structure

I have a recursive structure, where field of a structure is a reference to other struct of same type:
use std::collections::HashMap;
pub struct RecursiveStruct<'a> {
outer: Option<Box<&'a RecursiveStruct<'a>>>,
dict: HashMap<u32, String>
}
With this structure I also have couple of methods such as constructor, method which adds (k,v) pair to calee's field and a getter:
impl<'a> RecursiveStruct<'a> {
pub fn new(outer: Option<Box<&'a RecursiveStruct<'a>>>) -> Self {
let dict: HashMap<u32, String> = HashMap::new();
RecursiveStruct { outer, dict }
}
// searches for value corresponding to key in all struct layers
pub fn get(&self, key: u32) -> Result<String, ()> {
let item = self.dict.get(&key);
match item {
Some(x) => Ok(x.clone()),
None => {
match &self.outer {
Some(x) => x.get(key),
None => Err(())
}
}
}
}
// adds (key, val) to "innermost" instance of struct
pub fn add(&mut self, key:u32, val: String) {
self.dict.insert(key, val);
}
}
These methods work fine, but when I try to add a method, which tries to modify dict field in any of the inner layers, I get cannot borrow '***x' as mutable, as it is behind a '&' reference error.
pub fn re_assign(&mut self, key: u32, val: String) {
if self.dict.contains_key(&key) {
self.dict.insert(key, val);
} else {
match &mut self.outer {
Some(x) => x.re_assign(key, val.clone()),
None => println!("Such key couldn't be found!"),
};
}
}
Here is the link to playground.
You are using a &, but want a &mut, rust references are immutable by default:
Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=be82b8ba01dff60e106af9e59df8228e
use std::collections::HashMap;
pub struct RecursiveStruct<'a> {
outer: Option<Box<&'a mut RecursiveStruct<'a>>>,
dict: HashMap<u32, String>
}
impl<'a> RecursiveStruct<'a> {
pub fn new(outer: Option<Box<&'a mut RecursiveStruct<'a>>>) -> Self {
let dict: HashMap<u32, String> = HashMap::new();
RecursiveStruct { outer, dict }
}
pub fn get(&self, key: u32) -> Result<String, ()> {
let item = self.dict.get(&key);
match item {
Some(x) => Ok(x.clone()),
None => {
match &self.outer {
Some(x) => x.get(key),
None => Err(())
}
}
}
}
pub fn re_assign(&mut self, key: u32, val: String) {
if self.dict.contains_key(&key) {
self.dict.insert(key, val);
} else {
match &mut self.outer {
Some(x) => x.re_assign(key, val.clone()),
None => println!("Such key couldn't be found!"),
};
}
}
pub fn add(&mut self, key:u32, val: String) {
self.dict.insert(key, val);
}
}
fn main() {
// instantiate "outer" struct and set its field
let mut S = RecursiveStruct::new(None);
S.add(42, "Answer to the universe!".to_string());
// instantiate "inner" struct
let mut S1 = RecursiveStruct::new(Some(Box::new(&mut S)));
println!("{}", S1.get(42).unwrap()); // get the field of outer struct
// modify the field of outer struct
S1.re_assign(42, "The answer has been changed.".to_string());
println!("{}", S1.get(42).unwrap());
}

How do I mutate in a match which borrows an immutable value?

I can understand borrowing/ownership concepts in Rust, but I have no idea how to work around this case:
use std::collections::{HashMap, HashSet};
struct Val {
t: HashMap<u16, u16>,
l: HashSet<u16>,
}
impl Val {
fn new() -> Val {
Val {
t: HashMap::new(),
l: HashSet::new(),
}
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
self.l.insert(v);
}
fn remove(&mut self, v: &u16) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(r) => self.remove(r),
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.l.len());
}
playground
The compiler has the error:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:28:24
|
26 | match self.t.get(&v) {
| ------ immutable borrow occurs here
27 | None => false,
28 | Some(r) => self.remove(r),
| ^^^^^------^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
I don't understand why I can't mutate in the match arm when I did a get (read value) before; the self.t.get is finished when the mutation via remove begins.
Is this due to scope of the result (Option<&u16>) returned by the get? It's true that the lifetime of the result has a scope inside the match expression, but this design-pattern is used very often (mutate in a match expression).
How do I work around the error?
The declaration of function HashMap::<K,V>::get() is, a bit simplified:
pub fn get<'s>(&'s self, k: &K) -> Option<&'s V>
This means that it returns an optional reference to the contained value, not the value itself. Since the returned reference points to a value inside the map, it actually borrows the map, that is, you cannot mutate the map while this reference exists. This restriction is there to protect you, what would happen if you remove this value while the reference is still alive?
So when you write:
match self.t.get(&v) {
None => false,
//r: &u16
Some(r) => self.remove(r)
}
the captured r is of type &u16 and its lifetime is that of self.t, that is, it is borrowing it. Thus you cannot get a mutable reference to self, that is needed to call remove.
The simplest solution for your problem is the clone() solves every lifetime issue pattern. Since your values are of type u16, that is Copy, it is actually trivial:
match self.t.get(&v) {
None => false,
//r: u16
Some(&r) => self.remove(&r)
}
Now r is actually of type u16 so it borrows nothing and you can mutate self at will.
If your key/value types weren't Copy you could try and clone them, if you are willing to pay for that. If not, there is still another option as your remove() function does not modify the HashMap but an unrelated HashSet. You can still mutate that set if you take care not to reborrow self:
fn remove2(v: &u16, l: &mut HashSet<u16>) -> bool {
l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
//selt.t is borrowed, now we mut-borrow self.l, no problem
Some(r) => Self::remove2(r, &mut self.l)
}
}
You are trying to remove value from HashMap by using value you get, not key.
Only line 26 is changed Some(_) => self.remove(&v)
This will work:
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(_) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(1100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
play.rust
It seems that the following solution is good for primitive types like here u16. For other types, the ownership is moved.
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>,
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(&v) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
For other types, we must clone the value:
use std::collections::{HashMap, HashSet};
#[derive(Debug)]
struct Val {
t: HashMap<String, String>,
l: HashSet<String>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new(), l: HashSet::new() }
}
fn set(&mut self, k: String, v: String) {
self.l.insert(v.clone());
self.t.insert(k, v);
}
fn remove(&mut self, v: &String) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => {
let x = v.clone();
self.remove(&x)
}
}
}
fn do_task(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => self.l.insert(v.clone())
}
}
}
fn main() {
let mut v = Val::new();
v.set("AA".to_string(), "BB".to_string());
v.set("BB".to_string(), "CC".to_string());
println!("Start: {:#?}", v);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(&"AA".to_string()));
println!("Size after: {}", v.l.len());
println!("After: {:#?}", v);
println!("Task [Exist]: {}", v.do_task(&"BB".to_string()));
println!("Task [New]: {}", v.do_task(&"AA".to_string()));
println!("End: {:#?}", v);
}
But i'd like a solution that has no allocation

Rust function that accepts either HashMap and BtreeMap

fn edit_map_values(
map1: &mut HashMap<String, i128> || &mut BTreeMap<String, i128>){
for tuple in map1.iter_mut() {
if !map1.contains_key(&"key1") {
*tuple.1 += 1;
}
}
map1.insert(&"key2", 10);
}
How do I write one function that accepts either HashMap and BtreeMap like in the example above?
It is possible to abstract over types by using traits and for your specific use-case, you can take a look at this more constrained example.
use core::{borrow::Borrow, hash::Hash};
use std::collections::{BTreeMap, HashMap};
trait GenericMap<K, V> {
fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + Ord;
fn each_mut<F>(&mut self, cb: F)
where
F: FnMut((&K, &mut V));
fn insert(&mut self, key: K, value: V) -> Option<V>;
}
impl<K, V> GenericMap<K, V> for HashMap<K, V>
where
K: Eq + Hash,
{
fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + Ord,
{
self.contains_key(k)
}
fn each_mut<F>(&mut self, mut cb: F)
where
F: FnMut((&K, &mut V)),
{
self.iter_mut().for_each(|x| cb(x))
}
fn insert(&mut self, key: K, value: V) -> Option<V> {
self.insert(key, value)
}
}
impl<K, V> GenericMap<K, V> for BTreeMap<K, V>
where
K: Ord,
{
fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + Ord,
{
self.contains_key(k)
}
fn each_mut<F>(&mut self, mut cb: F)
where
F: FnMut((&K, &mut V)),
{
self.iter_mut().for_each(|x| cb(x))
}
fn insert(&mut self, key: K, value: V) -> Option<V> {
self.insert(key, value)
}
}
fn edit_map_values<T: GenericMap<String, i128>>(map: &mut T) {
map.each_mut(|(k, v)| {
if k != "key1" {
*v += 1;
}
});
map.insert("key2".into(), 10);
}
fn main() {
let mut hm: HashMap<String, i128> = [("One".into(), 1), ("Two".into(), 2)]
.iter()
.cloned()
.collect();
let mut btm: BTreeMap<String, i128> = [("Five".into(), 5), ("Six".into(), 6)]
.iter()
.cloned()
.collect();
dbg!(&hm);
dbg!(&btm);
edit_map_values(&mut hm);
edit_map_values(&mut btm);
dbg!(&hm);
dbg!(&btm);
}
Way back before the 1.0 release, there used to be Map and MutableMap traits, but they have been removed before stabilization. The Rust type system is currently unable to express these traits in a nice way due to the lack of higher kinded types.
The eclectic crate provides experimental collection traits, but they haven't been updated for a year, so I'm not sure they are still useful for recent versions of Rust.
Further information:
Does Rust have Collection traits?
No common trait for Map types? (Rust language forum)
Associated type constructors, part 1: basic concepts and introduction (blog post by Niko Matsakis)
Generic associated type RFC
While there is no common Map trait, you could use a combination of other traits to operate on an Iterator to achieve similar functionality. Although this might not be very memory efficient due to cloning, and also a bit involved depending on the kind of operation you are trying to perform. The operation you tried to do may be implemented like this:
fn edit_map_values<I>(map: &mut I)
where
I: Clone + IntoIterator<Item = (String, i128)> + std::iter::FromIterator<(String, i128)>,
{
// Since into_iter consumes self, we have to clone here.
let (keys, _values): (Vec<String>, Vec<_>) = map.clone().into_iter().unzip();
*map = map
.clone()
.into_iter()
// iterating while mutating entries can be done with map
.map(|mut tuple| {
if !keys.contains(&"key1".to_string()) {
tuple.1 += 1;
}
tuple
})
// inserting an element can be done with chain and once
.chain(std::iter::once(("key2".into(), 10)))
.collect();
// removing an element could be done with filter
// removing and altering elements could be done with filter_map
// etc.
}
fn main() {
use std::collections::{BTreeMap, HashMap};
{
let mut m = HashMap::new();
m.insert("a".to_string(), 0);
m.insert("key3".to_string(), 1);
edit_map_values(&mut m);
println!("{:#?}", m);
}
{
let mut m = BTreeMap::new();
m.insert("a".to_string(), 0);
m.insert("key3".to_string(), 1);
edit_map_values(&mut m);
println!("{:#?}", m);
}
}
Both times the output is the same, except for the order of the HashMap of course:
{
"a": 1,
"key2": 10,
"key3": 2,
}

Allow a function to accept a `T` or any `FnMut(T) -> T`

My goal is to make the last 2 lines of this code compile and the last assertion to pass:
struct State {
string: String
}
impl State {
fn string<F: FnMut(String) -> String>(mut self, mut f: F) -> Self {
self.string = f(self.string);
self
}
}
fn main() {
let state = State { string: String::from("foo") };
assert_eq!(state.string, "foo");
let state = state.string(|old| old + "bar");
assert_eq!(state.string, "foobar");
// let state = state.string(String::from("baz"));
// assert_eq!(state.string, "baz");
}
I thought this would be possible with traits and specialization, but the following code:
#![feature(specialization)]
trait Get<T> {
fn get(self, old: T) -> T;
}
impl<T> Get<T> for T {
default fn get(self, _: T) -> T {
self
}
}
impl<T, F> Get<T> for F where F: FnMut(T) -> T {
fn get(mut self, old: T) -> T {
self(old)
}
}
struct State {
string: String
}
impl State {
fn string<G: Get<String>>(mut self, g: G) -> Self {
self.string = g.get(self.string);
self
}
}
throws this error (live):
error[E0119]: conflicting implementations of trait `Get<_>`:
--> <anon>:13:1
|
13 | impl<T, F> Get<T> for F where F: FnMut(T) -> T {
| ^
|
note: conflicting implementation is here:
--> <anon>:7:1
|
7 | impl<T> Get<T> for T {
| ^
error: aborting due to previous error
So my question is, why is the second impl of Get not more "specific" than the first one, and is there any way in current stable or nightly Rust to get my original code to work?
Edit: I know implementing a trait for just one type would work, but I want a generic solution for any type as I want to be able to use this for any arbitrary fields of a struct.
For your concrete issue, you don't need specialization:
struct State {
string: String,
}
impl State {
fn string<F>(mut self, mut f: F) -> Self
where F: Thing
{
self.string = f.thing(self.string);
self
}
}
trait Thing {
fn thing(&mut self, s: String) -> String;
}
impl Thing for String {
fn thing(&mut self, _s: String) -> String {
self.clone()
}
}
impl<F> Thing for F
where F: FnMut(String) -> String
{
fn thing(&mut self, s: String) -> String {
(self)(s)
}
}
fn main() {
let state = State { string: String::from("foo") };
assert_eq!(state.string, "foo");
let state = state.string(|old| old + "bar");
assert_eq!(state.string, "foobar");
let state = state.string(String::from("baz"));
assert_eq!(state.string, "baz");
}
You may either want to require FnOnce or implement the trait for a &str. Right now, the allocation of the String is not being used, causing a bit of inefficiency.
You could then implement the trait multiple times for the interesting types:
struct State {
string: String,
vec: Vec<u8>,
}
impl State {
fn string<F>(mut self, mut f: F) -> Self
where F: Thing<String>
{
self.string = f.thing(self.string);
self
}
fn vec<F>(mut self, mut f: F) -> Self
where F: Thing<Vec<u8>>
{
self.vec = f.thing(self.vec);
self
}
}
trait Thing<T> {
fn thing(&mut self, s: T) -> T;
}
impl Thing<String> for String {
fn thing(&mut self, _s: String) -> String {
self.clone()
}
}
impl<F> Thing<String> for F
where F: FnMut(String) -> String
{
fn thing(&mut self, s: String) -> String {
(self)(s)
}
}
impl Thing<Vec<u8>> for Vec<u8> {
fn thing(&mut self, _s: Vec<u8>) -> Vec<u8> {
self.clone()
}
}
impl<F> Thing<Vec<u8>> for F
where F: FnMut(Vec<u8>) -> Vec<u8>
{
fn thing(&mut self, s: Vec<u8>) -> Vec<u8> {
(self)(s)
}
}
fn main() {
let state = State { string: String::from("foo"), vec: vec![1] };
assert_eq!(state.string, "foo");
let state = state.string(|old| old + "bar");
assert_eq!(state.string, "foobar");
let state = state.string(String::from("baz"));
assert_eq!(state.string, "baz");
assert_eq!(state.vec, [1]);
let state = state.vec(|mut old: Vec<u8>| {
old.push(2);
old
});
assert_eq!(state.vec, [1, 2]);
let state = state.vec(vec![3]);
assert_eq!(state.vec, [3]);
}
I believe that repetition could be handled by a macro:
macro_rules! thing {
($t: ty) => {
impl Thing<$t> for $t {
default fn thing(&mut self, _val: $t) -> $t {
self.clone()
}
}
impl<F> Thing<$t> for F
where F: FnMut($t) -> $t
{
fn thing(&mut self, val: $t) -> $t {
(self)(val)
}
}
}
}
thing!(String);
thing!(Vec<u8>);
Specialization doesn't work here because specialization only works for chains. That is, there exist functions that satisfy the impl
impl<T, F> Get<T> for F where F: FnMut(T) -> T
but not
impl<T> Get<T> for T
so the latter cannot specialize the former.
The simplest way to fix this is to just write a GetString trait instead of a Get<T> trait; that way you don't have to consider specialization on such malarkey at all.

Resources