Reputation: 2789
I want to write a program that will have many (maybe tens to hundreds) of references to the same number, say, "x" that will be updated multiple times per second. So I would like to just change the number in one place and have all the references to automatically be updated without having to reassign them (again, because there may be hundreds of them, leading to hundreds of reassignments.). If I can just update the number in one place, then I can run hundreds of product() updates right away.
Below is my attempt at this, where I have two structs referring to the same piece of f64 memory. I would like to update x one time only, and then all instances of my struct, thing1 and thing2, to calculate product
correctly.
#[derive(Debug)]
struct Thing<'a> {
high: &'a f64,
low: &'a f64,
}
impl Thing<'_> {
pub fn product(&self) -> f64 {
*self.high * *self.low
}
}
fn main() {
let mut x: f64 = 42.01;
let y: f64 = 7.95;
let w: f64 = 99.9;
let mut thing1: Thing = Thing { high: &w, low: &x };
let mut thing2: Thing = Thing { high: &y, low: &x };
println!("Before {:?} {}", thing1, thing1.product());
println!("Before {:?} {}", thing2, thing2.product());
// I want to swap or copy in a new value for the reference x, because
// it appears multiple times in different `Thing`s.
x = 500.7_f64;
println!("After {:?} {}", thing1, thing1.product());
println!("After {:?} {}", thing2, thing2.product());
}
The code above fails to compile with this error:
error[E0506]: cannot assign to `x` because it is borrowed
--> src/main.rs:25:5
|
18 | let mut thing1: Thing = Thing { high: &w, low: &x };
| -- borrow of `x` occurs here
...
25 | x = 500.7_f64;
| ^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
26 | println!("After {:?} {}", thing1, thing1.product());
| ------ borrow later used here
Upvotes: 1
Views: 503
Reputation: 26197
Edit: If the type used is copyable, then you should go with user4815162342's answer (which in this case it is as it's a f64
)
To be able to do that, you could use a Rc
(reference counted) RefCell
, i.e. Rc<RefCell<f64>>
. If you need to be able to share it across multiple threads, then you'd need an Arc
instead along with a Mutex
or RwLock
.
However, note that if x
is mutably borrowed (borrow_mut()
), and you attempt to borrow()
elsewhere, then that will result in a panic. So if those cases can happen, then consider using try_borrow()
and try_borrow_mut()
.
I'm only applying it to x
/low
, but in short your struct
would look like this:
struct Thing<'a> {
high: &'a f64,
low: Rc<RefCell<f64>>,
}
impl Thing<'_> {
pub fn product(&self) -> f64 {
*self.high * *self.low.borrow()
}
}
You'd create the instances like this:
let mut x = Rc::new(RefCell::new(42.01));
let mut thing1: Thing = Thing {
high: &w,
low: x.clone(),
};
let mut thing2: Thing = Thing {
high: &y,
low: x.clone(),
};
Then lastly you can modify x
by calling borrow_mut()
like this:
*x.borrow_mut() = 500.7;
Upvotes: 1
Reputation: 155126
You can use a Cell
which is, along with its cousin RefCell
, designed for the use case of modifying a shared value:
use std::cell::Cell;
#[derive(Debug)]
struct Thing<'a> {
high: &'a Cell<f64>,
low: &'a Cell<f64>,
}
impl Thing<'_> {
pub fn product(&self) -> f64 {
self.high.get() * self.low.get()
}
}
fn main() {
let x = Cell::new(42.01);
let y = Cell::new(7.95);
let w = Cell::new(99.9);
let thing1: Thing = Thing { high: &w, low: &x };
let thing2: Thing = Thing { high: &y, low: &x };
println!("Before {:?} {}", thing1, thing1.product());
println!("Before {:?} {}", thing2, thing2.product());
x.set(500.7_f64);
println!("After {:?} {}", thing1, thing1.product());
println!("After {:?} {}", thing2, thing2.product());
}
Upvotes: 3