Calling method on &mut self after accessing property in Rust [duplicate] - rust

This question already has answers here:
Borrowing references to attributes in a struct
(2 answers)
Passing mutable self reference to method of owned object
(2 answers)
Why does calling a method on a mutable reference involve "borrowing"?
(2 answers)
Rust borrow mutable self inside match expression
(1 answer)
How to end a borrow in a match or if let expression?
(2 answers)
Closed 5 years ago.
I need to match on an optional value that is on self, from a method, and based on that match, call a method on self that takes self mutably. I'm trying to do a pretty high-performance game, so as much as I'd like to dispense with mutability, I can't in this situation: the methods really do need to access the struct mutably, and they really do need to be dispatched based on the structs properties. Here is an MVCE:
enum Baz {
A,
B,
C,
}
struct Foo {
bar: Option<Baz>,
}
impl Foo {
pub fn dostuff(&mut self, fizz: i32) {
if let Some(ref b) = self.bar {
match b {
&Baz::A => self.do_a(fizz),
&Baz::B => self.do_b(fizz + 2),
&Baz::C => self.do_c(fizz + 1),
}
}
}
pub fn do_a(&mut self, f: i32) {
println!("A, with fizz {}", f);
}
pub fn do_b(&mut self, f: i32) {
println!("B, with fizz {}", f);
}
pub fn do_c(&mut self, f: i32) {
println!("C, with fizz {}", f);
}
}
fn main() {
let foo = Foo { bar: Some(Baz::A) };
foo.dostuff(3);
}
And here is the playground.
error[E0502]: cannot borrow `*self` as mutable because `self.bar.0` is also borrowed as immutable
--> src/main.rs:14:28
|
12 | if let Some(ref b) = self.bar {
| ----- immutable borrow occurs here
13 | match b {
14 | &Baz::A => self.do_a(fizz),
| ^^^^ mutable borrow occurs here
...
18 | }
| - immutable borrow ends here
I thought I'd made my peace with the borrow checker, but apparently not: I have no idea how to fix this, although I do know why this is happening. I would appreciate it if somebody explained how to avoid this in the future.

If you care about the references, as far as I know, Rust's rules forbid you from having such code. You have to either:
Copy or Clone your bar object and unwrap as how as you want.
Add some flag and make the code not have multiple references to the object. For example, add two variables which will tell you to what to do. You match your enum, set these variables and then you match these variables. This is less-useful than the first item here but this is a solution also.
Be more functional-like:
enum Baz {
A,
B,
C,
}
struct Foo {
bar: Option<Baz>,
}
impl Foo {
pub fn dostuff(&mut self, fizz: i32) {
let (method, arg) = match self.bar {
Some(ref b) => {
match b {
&Baz::A => (Self::do_a as fn(&mut Self, i32)>, fizz),
&Baz::B => (Self::do_b as fn(&mut Self, i32)>, fizz + 2),
&Baz::C => (Self::do_c as fn(&mut Self, i32)>, fizz + 1),
}
},
None => return,
};
method(self, arg);
}
pub fn do_a(&mut self, f: i32) {
println!("A, with fizz {}", f);
}
pub fn do_b(&mut self, f: i32) {
println!("B, with fizz {}", f);
}
pub fn do_c(&mut self, f: i32) {
println!("C, with fizz {}", f);
}
}
fn main() {
let mut foo = Foo { bar: Some(Baz::A) };
foo.dostuff(3);
}
By doing so you return a method which you wanna call with it's argument, so you just call what you need to. I am pretty sure this solution can be rewritten without using Box but just references to a method but I don't know how.

You can unwrap the Option(Baz) within the match instead of using if
let..
Declare foo as mutable
Here is the code ...
enum Baz {
A,
B,
C,
}
struct Foo {
bar: Option<Baz>,
}
impl Foo {
pub fn dostuff(&mut self, fizz: i32) {
match self.bar {
Some(Baz::A) => self.do_a(fizz),
Some(Baz::B) => self.do_b(fizz + 2),
Some(Baz::C) => self.do_c(fizz + 1),
None => {},
}
}
pub fn do_a(&mut self, f: i32) {
println!("A, with fizz {}", f);
}
pub fn do_b(&mut self, f: i32) {
println!("B, with fizz {}", f);
}
pub fn do_c(&mut self, f: i32) {
println!("C, with fizz {}", f);
}
}
fn main() {
let mut foo = Foo { bar: Some(Baz::B) };
foo.dostuff(3);
}

Related

How do I call a Box<dyn FnOnce> stored inside a struct inside an enum? [duplicate]

This question already has answers here:
FnOnce inside Enum: cannot move out of borrowed content
(1 answer)
Why is calling a FnOnce closure a move?
(1 answer)
Closed 10 months ago.
I store a FnOnce closure inside a struct inside an enum (Rust Playground):
pub struct ClosureContainer {
closure: Box<dyn FnOnce(i32) -> i32>,
}
pub enum MathOperation {
DoNothing,
RunOperation(ClosureContainer),
}
impl MathOperation {
pub fn doMath(&self, input: i32) -> i32 {
match self {
MathOperation::DoNothing => input,
MathOperation::RunOperation(closureContainer) => (closureContainer.closure)(input),
}
}
}
fn main() {
let f = Box::new(move |input: i32| 4 * input);
let closureContainer = ClosureContainer { closure: f };
let operation = MathOperation::RunOperation(closureContainer);
println!("{}", operation.doMath(5));
}
When I try to build, I get this error:
error[E0507]: cannot move out of `closureContainer.closure` which is behind a shared reference
--> src/main.rs:14:62
|
14 | MathOperation::RunOperation(closureContainer) => (closureContainer.closure)(input),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `closureContainer.closure` has type `Box<dyn FnOnce(i32) -> i32>`, which does not implement the `Copy` trait
How do I set things up so that I can call this function?
FnOnce can only be called once, so it needs to be consumed. If it's consumed, then the ClosureContainer must also be consumed (otherwise it's just an invalid struct). The fix, then, is to use self instead of &self in doMath:
pub struct ClosureContainer {
closure: Box<dyn FnOnce(i32) -> i32>,
}
pub enum MathOperation {
DoNothing,
RunOperation(ClosureContainer),
}
impl MathOperation {
pub fn doMath(self, input: i32) -> i32 {
match self {
MathOperation::DoNothing => input,
MathOperation::RunOperation(closureContainer) => (closureContainer.closure)(input),
}
}
}
fn main() {
let f = Box::new(move |input: i32| 4 * input);
let closureContainer = ClosureContainer { closure: f };
let operation = MathOperation::RunOperation(closureContainer);
println!("{}", operation.doMath(5));
}

How to define an iterator in Rust over a struct that contains items that are iterable?

How does one define an iterator in Rust over a struct that contains items that are already iterable? Here's one attempt at the iterator
use rand;
// Structure of items
struct Foo {
foo: Vec<f64>,
bar: Vec<i64>,
}
// Iterator for the structure
struct FooIter {
foo: Iterator,
bar: Iterator,
}
// Method that provides the iterator for use
impl Foo {
fn iter(&self) -> FooIter {
FooIter {
foo: self.foo.iter().peek(),
bar: self.bar.iter().peek(),
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl Iterator for FooIter {
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
match (self.foo.peek(), self.far.peek()) {
(Some(_), Some(_)) => {
if rand::random() {
self.foo.next()
} else {
self.bar.next()
}
}
(Some(_), None) => self.foo.next(),
(None, Some(_)) => self.bar.next(),
(None, None) => None,
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
bar: vec![5, 6],
};
for item in fuz.iter() {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
In short, the struct Foo contains two vectors and I'd like an iterator that jumps back and forth between the two elements randomly. Certainly, there are many mistakes here, but at the core, I don't understand how to create a struct that carries the iterators for the items foo and far because Rust defines iterators as a trait and not a type.
You must at some point define what Item the Iterator will produce, for example Iterator<Item = &'a f64>. Let simplify and transform to Iterator<Item = f64>, because f64 is Copy so it's often better to avoid the reference if you don't need it.
So, then we will have compile error:
error[E0277]: the size for values of type `(dyn std::iter::Iterator<Item = f64> + 'static)` cannot be known at compilation time
--> src/main.rs:11:5
|
11 | foo: std::iter::Iterator<Item = f64>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::iter::Iterator<Item = f64> + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: only the last field of a struct may have a dynamically sized type
To avoid dynamic type and fix the error at the same time, let's define some generic type:
// Iterator for the structure
struct FooIter<F, I> {
foo: F,
bar: I,
}
We add the necessary on our implementation of Iterator:
impl<F, I> Iterator for FooIter<F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
And we must change how we generate FooIter, this time we will use a magic keyword impl, this avoid to write the real type of the Iterator that can be very long and unclear, the compiler will infer the type for us. Also, we must bound the type to the lifetime of &self because it must be borrow as long as the iterator live, simply declare 'a lifetime and add + 'a will do the job:
fn iter<'a>(
&'a self,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().copied(),
bar: self.bar.iter().copied(),
}
}
Here we finish the basic, the next problem is that your code doesn't produce Bar type in next(), so we must correct your code, also it's would be nice to create a propre random generator. So here the final snippet:
use rand::{rngs::ThreadRng, thread_rng, Rng};
// Structure of items
struct Foo {
foo: Vec<f64>,
bar: Vec<i64>,
}
// Iterator for the structure
struct FooIter<'r, F, I> {
foo: F,
bar: I,
rng: &'r mut ThreadRng,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a, 'r: 'a>(
&'a self,
rng: &'r mut ThreadRng,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().copied(), // nigthly feature, use cloned() for stable
bar: self.bar.iter().copied(),
rng,
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl<'r, F, I> Iterator for FooIter<'r, F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
{
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
if self.rng.gen() {
self.foo
.next()
.map(|x| Bar::MyFloat(x))
.or_else(|| self.bar.next().map(|x| Bar::MyInt(x)))
} else {
self.bar
.next()
.map(|x| Bar::MyInt(x))
.or_else(|| self.foo.next().map(|x| Bar::MyFloat(x)))
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
bar: vec![5, 6],
};
for item in fuz.iter(&mut thread_rng()) {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
Note, if you still want a Peekable<Iterator> then just do:
struct FooIter<'r, F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
{
foo: Peekable<F>,
bar: Peekable<I>,
rng: &'r mut ThreadRng,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a, 'r: 'a>(
&'a self,
rng: &'r mut ThreadRng,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().copied().peekable(),
bar: self.bar.iter().copied().peekable(),
rng,
}
}
}
#Stargateur largely has me sorted, but I wanted to include two separate codes to complete things. The following is the fixed code that's slightly closer to my original attempt, which works on Rust 1.34.1:
// Structure of items
struct Foo {
foo: Vec<f64>,
far: Vec<i64>,
}
// Iterator for the structure
struct FooIter<FloatIter, IntIter>
where
FloatIter: Iterator<Item = f64>,
IntIter: Iterator<Item = i64>,
{
foo: std::iter::Peekable<FloatIter>,
far: std::iter::Peekable<IntIter>,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a>(
&'a self,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().cloned().peekable(),
far: self.far.iter().cloned().peekable(),
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl<FloatIter, IntIter> Iterator for FooIter<FloatIter, IntIter>
where
FloatIter: Iterator<Item = f64>,
IntIter: Iterator<Item = i64>,
{
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
match (self.foo.peek(), self.far.peek()) {
(Some(_), Some(_)) => {
if rand::random() {
self.foo.next().map(|x| Bar::MyFloat(x))
} else {
self.far.next().map(|x| Bar::MyInt(x))
}
}
(Some(_), None) => self.foo.next().map(|x| Bar::MyFloat(x)),
(None, Some(_)) => self.far.next().map(|x| Bar::MyInt(x)),
(None, None) => None,
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
far: vec![5, 6],
};
for item in fuz.iter() {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
What helped me understand what was going on is that FooIter parametrizes its arguments on generic types. These types are inferred by using impl Trait in the return position within the iter method for Foo. That said, I was able to write a similar code without using this inference:
extern crate rand;
// Structure of items
struct Foo {
foo: Vec<f64>,
far: Vec<i64>,
}
// Iterator for the structure
struct FooIter<'a> {
foo: std::iter::Peekable<std::slice::Iter<'a, f64>>,
far: std::iter::Peekable<std::slice::Iter<'a, i64>>,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a>(&'a self) -> FooIter<'a> {
FooIter {
foo: self.foo.iter().peekable(),
far: self.far.iter().peekable(),
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl<'a> Iterator for FooIter<'a> {
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
match (self.foo.peek(), self.far.peek()) {
(Some(_), Some(_)) => {
if rand::random() {
self.foo.next().map(|x| Bar::MyFloat(x.clone()))
} else {
self.far.next().map(|x| Bar::MyInt(x.clone()))
}
}
(Some(_), None) => self.foo.next().map(|x| Bar::MyFloat(x.clone())),
(None, Some(_)) => self.far.next().map(|x| Bar::MyInt(x.clone())),
(None, None) => None,
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
far: vec![5, 6],
};
for item in fuz.iter() {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
This is almost certainly the wrong way to do things, but I wanted to see if it was possible. I determined the iterator type by compiling the code:
fn main() {
let x = vec![1.2, 2.3, 3.4];
let y: i32 = x.iter().peekable();
}
which gave the compiler error:
error[E0308]: mismatched types
--> junk.rs:4:19
|
4 | let y: i32 = x.iter().peekable();
| ^^^^^^^^^^^^^^^^^^^ expected i32, found struct `std::iter::Peekable`
|
= note: expected type `i32`
found type `std::iter::Peekable<std::slice::Iter<'_, {float}>>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
This contains the type of what I was looking for. Again, this is almost certainly the wrong thing to do, but it helped me understand the provided answer.

How to change the variable from inside Fn closure in Rust?

I have the following code (playground):
struct A {
pub vec: Vec<u64>,
}
impl A {
fn perform_for_all<F: Fn(&mut u64)>(&mut self, f: F) {
for mut i in &mut self.vec {
f(i);
}
}
}
fn main() {
let mut a = A {
vec: vec![1, 3, 44, 2, 4, 5, 6],
};
let mut done = false;
a.perform_for_all(|v| {
println!("value: {:?}", v);
done = true;
});
if !done {
a.perform_for_all(|v| {
println!("value {:?}", v);
});
}
}
The following errors occur:
error[E0594]: cannot assign to `done`, as it is a captured variable in a `Fn` closure
--> src/main.rs:21:9
|
21 | done = true;
| ^^^^^^^^^^^ cannot assign
|
help: consider changing this to accept closures that implement `FnMut`
--> src/main.rs:19:23
|
19 | a.perform_for_all(|v| {
| _______________________^
20 | | println!("value: {:?}", v);
21 | | done = true;
22 | | });
| |_____^
I have a list of loaded objects and a list of objects in a database. I need a function that takes a closure and executes it on the loaded objects and if we don't have the objects in the list, execute it on a list of objects from the database.
That function looks like:
pub fn perform_for_match_with_mark<F>(&mut self, mark: MatchMark, f: F)
where
F: Fn(&mut GameMatch),
{
self.perform_for_all_matches(
|m| {
// runtime list
if let Game::Match(ref mut gm) = *m {
if gm.match_stamp().mark == mark {
f(gm);
}
}
},
None,
);
// if we have called `f` above - don't execute lines below.
let tx = self.match_tx.clone();
GamesDatabase::perform_for_match_with_mark(mark, |ms| {
// database
self.perform_for_all_matches(
|m| {
if let Game::Match(ref gm) = *m {
if gm.match_stamp().id == ms.id {
f(&mut GameMatch::new_with_match_stamp(
tx.clone(),
ms.clone(),
gm.needs_server_set,
gm.server_id,
))
}
}
},
None,
);
});
}
We have to operate on objects from the database only if we were unable to find them in runtime list. That is why I decided to make a variable which says "we already found these objects in the list, leave the database alone".
Change your perform_for_all function to use FnMut instead of Fn:
fn perform_for_all<F>(&mut self, mut f: F)
where
F: FnMut(&mut u64),
{
for mut i in &mut self.vec {
f(&mut i);
}
}
As Peter said, there is some compiler magic going on.
The signature for Fn::call is:
extern "rust-call" fn call(&self, args: Args) -> Self::Output
This takes an immutable reference to self, which is why you can't modify any of the captured variables.
The signature for FnMut::call_mut lets you mutate variables because it takes &mut self:
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output
By changing your closure from Fn to FnMut, you allow it to modify its captured variables, given that the references you pass to it are mutable.
Just to expand a little on SplittyDev's answer.
When you use a closure, the compiler does some magic to let the closure access variables in its environment. Effectively it will create a new struct, whose members are the variables that you tried to access.
It's not exactly this (which won't actually compile), but it's a reasonable approximation conceptually:
struct Closure_1 {
done: bool
}
impl FnMut<&mut u64> for Closure_1 {
fn call_mut(&mut self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true;
}
}
And when you call it, those variables will be borrowed or copied (or moved if you use move keyword).
let mut c1 = Closure_1 { done : done };
a.perform_for_all(|v| c1.call(&v));
done = c1.done;
When the closure modifies its environment, it cannot be a Fn because it must also mutate the variables on itself:
impl Fn<&mut u64> for Closure_1 {
fn call(&self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true; // Can't do this because self is not a mutable ref
}
}
See The Rust Programming Language section on closures and their environment for more information.

Borrow checker problems while trying to mutate a struct in a match

I'm trying to implement lazy "thunks" in Rust and I just can't figure out how to get my code to pass the borrow checker. The basic idea is that a Thunk<T> can only be in one of two ThunkStates:
Forced which carries its value of type T;
Unforced, which carries a boxed closure that returns a T.
My naïve code goes like this:
pub struct Thunk<T>(ThunkState<T>);
enum ThunkState<T> {
Forced(T),
Unforced(Box<Fn() -> T>),
}
impl<T> Thunk<T> {
pub fn new<F>(f: F) -> Thunk<T>
where
F: Fn() -> T + 'static,
{
Thunk(ThunkState::Unforced(Box::new(f)))
}
pub fn get(&mut self) -> &T {
match self.0 {
ThunkState::Forced(ref t) => &t,
ThunkState::Unforced(ref f) => {
// TROUBLE HERE
self.0 = ThunkState::Forced(f());
self.get()
}
}
}
}
I get the following two compilation errors:
error[E0506]: cannot assign to `self.0` because it is borrowed
--> src/main.rs:21:17
|
19 | ThunkState::Unforced(ref f) => {
| ----- borrow of `self.0` occurs here
20 | // TROUBLE HERE
21 | self.0 = ThunkState::Forced(f());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.0` occurs here
error[E0502]: cannot borrow `*self` as mutable because `self.0.0` is also borrowed as immutable
--> src/main.rs:22:17
|
19 | ThunkState::Unforced(ref f) => {
| ----- immutable borrow occurs here
...
22 | self.get()
| ^^^^ mutable borrow occurs here
23 | }
24 | }
| - immutable borrow ends here
I've gone through various iterations of trying out stuff (e.g., match *self.0, using &mut in the ThunkState patterns, and a few variations), but try as I may, I can't figure out how to fix it.
Am I attempting to do something that doesn't make sense?
If not, what makes this example so tricky, and how do I get it right?
Staring at it a bit more, I've formulated the following hypothesis: the assignment to self.0 would invalidate the f reference in that match branch. Is this right? And if so, then how do I achieve what I'm trying to do—discard the closure after I use it?
Your original code works as-is with non-lexical lifetimes enabled (available in the 2018 edition):
pub struct Thunk<T>(ThunkState<T>);
enum ThunkState<T> {
Forced(T),
Unforced(Box<Fn() -> T>),
}
impl<T> Thunk<T> {
pub fn new<F>(f: F) -> Thunk<T>
where
F: Fn() -> T + 'static,
{
Thunk(ThunkState::Unforced(Box::new(f)))
}
pub fn get(&mut self) -> &T {
match self.0 {
ThunkState::Forced(ref t) => t,
ThunkState::Unforced(ref f) => {
self.0 = ThunkState::Forced(f());
self.get()
}
}
}
}
This is now supported because the tracking of what is borrowed in which match arm is now more precise.
This is indeed a tricky problem, but it is possible. For stuff like this, it's often a good idea to search for helpful functions in the mem module.
I've come up with a solution, but I think that there is still a lot of room for improvement.
pub fn get(&mut self) -> &T {
let mut f = None;
if let ThunkState::Unforced(ref mut f_ref) = self.0 {
f = Some(std::mem::replace(f_ref, unsafe {
std::mem::uninitialized()
}));
}
if let Some(f) = f {
self.0 = ThunkState::Forced(f());
}
match self.0 {
ThunkState::Forced(ref t) => &t,
_ => unreachable!(),
}
}
This compiles fine, at least. The trick is to use mem::replace to get the important value out of self first. Additionally, you can avoid the unsafe by creating some kind of dummy value (like Box::new(|| panic!())).
I found something that semi-works:
pub struct Thunk<T>(ThunkState<T>);
enum ThunkState<T> {
Forced(T),
Unforced(Box<Fn() -> T>),
}
impl<T> Thunk<T> {
pub fn new<F>(f: F) -> Thunk<T>
where
F: Fn() -> T + 'static,
{
Thunk(ThunkState::Unforced(Box::new(f)))
}
pub fn get(&mut self) -> &T {
match self.0 {
ThunkState::Forced(ref t) => &t,
// Don't actually bind a variable to the boxed closure here.
ThunkState::Unforced(_) => {
self.0 = ThunkState::Forced(self.0.compute());
self.get()
}
}
}
}
impl<T> ThunkState<T> {
fn compute(&self) -> T {
match self {
&ThunkState::Unforced(ref f) => f(),
// FIXME: get rid of this panic?
&ThunkState::Forced(_) => panic!("case never used"),
}
}
}
It compiles, but after trying to use this type what I've learned is that I probably need interior mutability.
The problem is that you're trying to do too much (for the sake of avoiding return) within the lexical borrowing context of match self.0 { ... }.
What you can do is:
Move results of calculations performed on values you need to borrow from self.0 into variables defined in an outer scope.
Exit early on paths where those values aren't needed
Consume the values after the match statement
Applied to your example, a solution could be:
pub struct Thunk<T>(ThunkState<T>);
enum ThunkState<T> {
Forced(T),
Unforced(Box<Fn() -> T>),
}
impl<T> Thunk<T> {
pub fn new<F>(f: F) -> Thunk<T>
where
F: Fn() -> T + 'static,
{
Thunk(ThunkState::Unforced(Box::new(f)))
}
pub fn get(&mut self) -> &T {
let func_result: T;
match self.0 {
ThunkState::Forced(ref t) => {
return &t;
}
ThunkState::Unforced(ref f) => {
func_result = f();
}
}
self.0 = ThunkState::Forced(func_result);
self.get()
}
}

Calling two member functions that work with different fields at the same time [duplicate]

It seems that if you borrow a reference to a struct field, the whole struct is considered borrowed. I've managed to isolate and example of what I want to do. I just want to get a "read-only" reference to a field in B to obtain some data and then modify another field of B. Is there a idiomatic Rust way to do this?
struct A {
i: i32,
}
struct B {
j: i32,
a: Box<A>,
}
impl B {
fn get<'a>(&'a mut self) -> &'a A {
&*self.a
}
fn set(&mut self, j: i32) {
self.j = j
}
}
fn foo(a: &A) -> i32 {
a.i + 1
}
fn main() {
let a = Box::new(A { i: 47 });
let mut b = B { a: a, j: 1 };
let a_ref = b.get();
b.set(foo(a_ref));
}
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> src/main.rs:27:5
|
26 | let a_ref = b.get();
| - first mutable borrow occurs here
27 | b.set(foo(a_ref));
| ^ second mutable borrow occurs here
28 | }
| - first borrow ends here
It's a feature of the language. From the compiler point of view, there is no way for it to know that it's safe to call your set() function while a is borrowed via get().
Your get() function borrows b mutably, and returns a reference, thus b will remain borrowed until this reference goes out of scope.
You have several way of handling this:
Separate your two fields into two different structs
Move the code which needs to access both attribute inside a method of B
Make your attributes public, you will thus be able to directly get references to them
Compute the new value before setting it, like this:
fn main() {
let a = Box::new(A { i: 47 });
let mut b = B { a: a, j: 1 };
let newval = {
let a_ref = b.get();
foo(a_ref)
};
b.set(newval);
}
Expanding a bit on Levans' answer
Move the code which needs to access both attribute inside a method of B
That might look like this at a first pass:
impl B {
fn do_thing(&mut self) {
self.j = self.a.foo()
}
}
However, this hard-codes the call to foo. You could also accept a closure to allow this to be more flexible:
impl B {
fn update_j_with_a<F>(&mut self, f: F)
where
F: FnOnce(&mut A) -> i32,
{
self.j = f(&mut self.a)
}
}
// ...
b.update_j_with_a(|a| a.foo())
Separate your two fields into two different structs
This is also applicable when you have borrowed two disjoint subsets of attributes. For example:
struct A {
description: String,
name: String,
age: u8,
money: i32,
}
impl A {
fn update_description(&mut self) {
let description = &mut self.description;
*description = self.build_description()
// cannot borrow `*self` as immutable because `self.description` is also borrowed as mutable
}
fn build_description(&self) -> String {
format!(
"{} is {} years old and has {} money",
self.name,
self.age,
self.money
)
}
}
fn main() {}
Can be changed into
struct A {
description: String,
info: Info,
}
struct Info {
name: String,
age: u8,
money: i32,
}
impl A {
fn update_description(&mut self) {
let description = &mut self.description;
*description = self.info.build_description()
}
}
impl Info {
fn build_description(&self) -> String {
format!(
"{} is {} years old and has {} money",
self.name,
self.age,
self.money
)
}
}
fn main() {}
You can combine these two steps (and I'd say that it's better practice) and move the method onto the inner struct.

Resources