How to access a field of a struct within a struct? - rust

I have a struct container of Children and a method pop() that removes the last added Child and returns it's a value:
struct Child {
a: i32,
b: String,
}
struct Container<'a> {
vector: &'a mut Vec<Child>,
}
impl<'a> Container<'a> {
fn pop(&mut self) -> i32 {
return self.vector.pop().a;
}
}
I get the error during compilation:
error: no field `a` on type `std::option::Option<Child>`
--> src/main.rs:12:34
|
12 | return self.vector.pop().a;
| ^
Does the scope of Container's pop() not allow access to values of its Children's scope?

Vec::pop returns an Option<Child>, not a Child. This allows it to have something reasonable to return in case there are no elements in the Vec to pop off. To get at the a that may be inside, you can convert from Option<Child> to Child using unwrap(), but that will cause your program to panic if the Vec was empty. The code for that would look like this:
fn pop(&mut self) -> i32 {
return self.vector.pop().unwrap().a;
}
Another option would be to more closely copy Vec's behavior, and return None in case there are no elements. You could do that using Option's map method:
fn pop(&mut self) -> Option<i32> {
return self.vector.pop().map(|child| child.a)
}

Related

How can I mutate fields of a struct while referencing other fields?

Here's an example of a problem I ran into:
pub struct Item {
name: String,
value: LockableValue, // another struct that I'd like to mutate
}
impl Item {
pub fn name(&self) -> &str {
&self.name
}
pub fn value_mut(&mut self) -> &mut LockableValue {
&self.value
}
}
pub fn update(item: &mut Item) {
let value = item.value_mut();
value.change(); // how it changes is unimportant
println!("Updated item: {}", item.name());
}
Now, I know why this fails. I have a mutable reference to item through the mutable reference to the value.
If I convert the reference to an owned String, it works fine, but looks strange to me:
pub fn update(item: &mut Item) {
let name = { item.name().to_owned() };
let value = item.value_mut();
value.change(); // how it changes is unimportant
println!("Updated item: {}", name); // It works!
}
If I let value reference drop, then everything is fine.
pub fn update(item: &mut Item) {
{
let value = item.value_mut();
value.change(); // how it changes is unimportant
}
println!("Updated item: {}", item.name()); // It works!
}
The value.change() block is rather large, and accessing other fields in item might be helpful. So while I do have solutions to this issue, I'm wondering if there is a better (code-smell) way to do this. Any suggestions?
My intention behind the above structs was to allow Items to change values, but the name should be immutable. LockableValue is an tool to interface with another memory system, and copying/cloning the struct is not a good idea, as the memory is managed there. (I implement Drop on LockableValue to clean up.)
I was hoping it would be straight-forward to protect members of the struct from modification (even if it were immutable) like this... and I can, but it ends up looking weird to me. Maybe I just need to get used to it?
You could use interior mutability on only the part that you want to mutate by using a RefCell like ths:
use std::cell::{RefCell, RefMut};
pub struct LockableValue;
impl LockableValue {
fn change(&mut self) {}
}
pub struct Item {
name: String,
value: RefCell<LockableValue>, // another struct that I'd like to mutate
}
impl Item {
pub fn name(&self) -> &str {
&self.name
}
pub fn value_mut(&self) -> RefMut<'_, LockableValue> {
self.value.borrow_mut()
}
}
pub fn update(item: &Item) {
let name = item.name();
let mut value = item.value_mut();
value.change(); // how it changes is unimportant
println!("Updated item: {}", name);
}
That way you only need a shared reference to Item and you don't run into an issue with the borrow checker.
Not that this forces the borrow checks on value to be done at runtime though and thus comes with a performance hit.

idiomatic mutable arena traversal dependent on immutable member

How should I rewrite the following code idiomatically?
The problem seems to be that traversal could be modified during action(). One solution would be to create a temporary copy of traversal inside of traverse, but that would be a burden if traversal is large.
Maybe Idiomatically access an element of a vector mutably and immutably is the canonical version of this, but I am not sure (and have not fully understood the referenced issue)?
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(&mut self, foo_idx: usize) {
// mutate self.arena[foo_idx]
}
fn traverse(&mut self) {
for i in &self.traversal {
self.action(*i);
}
}
}
current error:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:15:13
|
14 | for i in &self.traversal {
| ---------------
| |
| immutable borrow occurs here
| immutable borrow later used here
15 | self.action(*i);
| ^^^^^^^^^^^^^^^ mutable borrow occurs here
In your case, Bar has two apparently disjoint fields, so it should be possible to hold references to each of them at the same time. The problem, though, is even though action only touches arena, rust assesses the borrowing rules based on the function's prototype:
fn action(&mut self, foo_idx: usize)
which indicates that it takes a mutable borrow of self.
Here are a few possible solutions:
Inline
If the mutation being performed inside action is simple, and isn't called from anywhere else, then just do it inline inside traverse:
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn traverse(&mut self) {
for i in &self.traversal {
// mutate arena here
self.arena[*i] = Foo{};
}
}
}
Refactor
If traversal and arena are really two different things, maybe it makes more sense for them to belong to separate types, like this:
struct Foo {}
struct Baz(Vec<Foo>);
impl Baz {
fn action(&mut self, foo_idx: usize) {
self.0[foo_idx] = Foo{};
}
}
struct Bar {
traversal: Vec<usize>,
arena: Baz,
}
impl Bar {
fn traverse(&mut self) {
for i in &self.traversal {
self.arena.action(*i);
}
}
}
Associated Function
A variation on the above theme is to simply change the prototype of action so that it takes only the field it will modify as input. action is no longer a method as such - it does not take self - but is still associated with the type Bar:
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(arena: &mut Vec<Foo>, foo_idx: usize) {
arena[foo_idx] = Foo{};
}
fn traverse(&mut self) {
for i in &self.traversal {
Self::action(&mut self.arena, *i);
}
}
}
Traverse via index
Instead of iterating the traversal Vec, you can avoid taking the initial immutable borrow like this:
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(&mut self, foo_idx: usize) {
// mutate self.arena[foo_idx]
}
fn traverse(&mut self) {
for traversal_idx in 0..self.traversal.len() {
let i = self.traversal[traversal_idx];
self.action(i);
}
}
}
I can think of two ways to do this (plus an easier way that's less general). The first is to destructure the struct so you aren't dealing with self anymore, but only its data. Then the data are independent so you the ownership of arena and traverse won't conflict anymore because they are independent. The disadvantage is that the function parameters get more complex.
struct Foo {
pub i: i32,
}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(arena: &mut Vec<Foo>, foo_idx: usize) {
arena[foo_idx].i += 1;
}
fn traverse(&mut self) {
let Bar { traversal, arena } = self;
for i in traversal {
Self::action(arena, *i);
}
}
}
The other way has a nicer API but is more risky: take just one value out of self (use std::mem::take or std::mem::replace) so you can reference it with no dependency on self. This is a liability is because you need to remember to put the value back in afterwards, and if you are using Result, ? can make the function return early and not execute the cleanup.
struct Foo {
pub i: i32,
}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(&mut self, foo_idx: usize) {
self.arena[foo_idx].i += 1;
}
fn traverse(&mut self) {
let traversal = std::mem::take(&mut self.traversal);
for i in traversal.iter() {
self.action(*i);
}
self.traversal = traversal;
}
}
If your real code is only iterating as in this example, there is an easier way to solve it: change the vector to Rc<Vec<Foo>>. That way you can use Rc::clone to get a copy of the variable that's independent of self, but points at the same data.

Why RefCell's `into_inner` requires a move?

I have a situation where I have to move a struct from one object to another through a &mut self. Take a look:
pub struct MyStruct {
//no copy trait
device: Device
}
impl MyStruct {
pub fn finalize(&mut self) {
//error: cannot move since I borrowed
let interface = InterfaceBuilder::new(self.device)
}
}
First of all, why I cannot move something out of a borrowed mutable reference? Borrowed mutables are exclusive, there's no chance another code is looking into it.
Well, to address this problem I changed to
pub struct MyStruct {
//no copy trait
device: RefCell<Device>
}
impl MyStruct {
pub fn finalize(&mut self) {
//error on `self.device`: cannot move out of `self.device` which is behind a mutable reference
let interface = InterfaceBuilder::new(self.device.into_inner())
}
}
I know why the error occurs:
pub fn into_inner(self) -> T
calling into_inner makes self.device move. Why RefCell simply does not have an implementation pub fn into_inner(&mut self) -> T? I don't see a problem.
You cannot move out of a mutable reference because that would leave the original object incomplete.
Consider this code:
struct MyStruct {
s: String
}
fn finalize(f: &mut MyStruct) {
let _x = f.s; //error E0507!
}
fn main() {
let mut my = MyStruct {
s: "hi".into()
};
finalize(&mut my);
println!("{}", my.s); //what should this do?
}
Then, RefCell::into_inner(&mut self) -> T has the same problem. You could call it twice in a row and you would get two T values where before there was only one. And that, for a non Copy type is impossible.
If you want this function to consume the inner value, probably it should consume the outer value too:
fn finalize(f: MyStruct) {
let _x = f.s;
}
If you really want to move a value out of a mutable reference, you must leave something valid in its place. The easiest way is to declare an Option and use take() to steal and replace it with a None:
struct MyStruct {
s: Option<String>
}
fn finalize(f: &mut MyStruct) {
let _x = f.s.take();
}
Naturally, Option::take returns an Option so that if you call it twice, the second time you get None. If you are positive you have a value you can do take().uwnrap().
Alternatively, if your field type is Default you can use std::mem::take that replaces it with a default-created value:
struct MyStruct {
s: Vec<i32>
}
fn finalize(f: &mut MyStruct) {
let _x = std::mem::take(&mut f.s);
}
PS #1: there is Cell::take(&self) -> T, but only if T implements Default. It works just like std::mem::take but with a non-mutable reference.
PS #2: there is also unsafe fn ManuallyDrop::take(slot: &mut ManuallyDrop<T>) -> T, that is intented to be used in advanced drop implementations. But it is unsafe so it should never be your first option: if you call it twice you will get undefined behavior.

how to implement an iterator that delegates to HashMap::values()

I am trying to implement a datastructure to store 'registers' in groups. There is a master list which I am considering the owner of the register data.
I have the following:
use std::collections::hash_map::HashMap;
pub struct Register {
pub name: String,
pub address: u16,
}
// map with references to 'master' list of registers
type RegisterMap<'a> = HashMap<String, &'a Register>;
struct RegisterGroup<'a> {
start_address: u16,
registers: RegisterMap<'a>,
}
struct RegisterGroupIter<'a> {
inner: std::collections::hash_map::Values<'a,String,&'a Register>,
}
impl<'a> Iterator for RegisterGroupIter<'a> {
type Item = &'a Register;
fn next(&mut self) -> Option<&'a Register> {
self.inner.next()
}
}
impl<'a> RegisterGroup<'a> {
// return iterator over references to Register
fn registers(&self) -> RegisterGroupIter {
RegisterGroupIter {
inner: self.registers.values(),
}
}
}
Is this reasonable/idiomatic? If so what is the correct setup for the item type wrt references/lifetimes etc? Otherwise what should I be doing instead?
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:22:9
|
21 | fn next(&mut self) -> Option<&'a Register> {
| -------------------- expected `std::option::Option<&'a Register>` because of return type
22 | self.inner.next()
| ^^^^^^^^^^^^^^^^^ expected struct `Register`, found `&Register`
|
= note: expected enum `std::option::Option<&'a Register>`
found enum `std::option::Option<&&'a Register>`
Since the values iterator of a HashMap yields references to the values type, and the values type is a reference itself in this case, the iterator items are of type &&Register. This means you need to dereference the items before returning them in your iterator. The easiest way to dereference inside an option is to use the copied() method:
impl<'a> Iterator for RegisterGroupIter<'a> {
type Item = &'a Register;
fn next(&mut self) -> Option<&'a Register> {
self.inner.next().copied()
}
}
I'm not sure why you store the name both as the hash map key and inside the Register struct. I'd usually try to normalize the data and only sore the name as the map keys.
You don't really need to implement your own iterator type here. Directly returning the values iterator of the hash map will work just fine:
impl RegisterGroup<'_> {
fn registers(&self) -> impl Iterator<Item = &Register> {
self.registers.values().copied()
}
}

Cannot move out of borrowed content from closure return value

I found this problem when working on a mid-size project. The following snippet is a minimal summary of the problem.
In the following code I try to map a list of enum variants into a Set of different enum variants. I use a closure so I can capture a mutable reference to my_list which is a list of source enum variants. The closure is then kept inside a MyType instance so it can be called later and the result used inside another method.
To keep the closure, I used a FnMut trait inside a Box. I also wrapped that inside an Option so I can set the closure after instance creation.
I based this a bit from the question asked here: structs with boxed vs. unboxed closures
use std::collections::HashSet;
enum Numbers {
One,
Two,
Three,
}
#[derive(Eq, PartialEq, Hash)]
enum Romans {
I,
II,
III,
}
struct MyType<'a> {
func: Option<Box<dyn FnMut() -> HashSet<Romans> + 'a>>,
}
impl<'a> MyType<'a> {
pub fn set_func<F>(&mut self, a_func: F)
where F: FnMut() -> HashSet<Romans> + 'a {
self.func = Some(Box::new(a_func));
}
pub fn run(&mut self) {
let result = (self.func.unwrap())();
if result.contains(&Romans::I) {
println!("Roman one!");
}
}
}
fn main() {
let my_list = vec![Numbers::One, Numbers::Three];
let mut my_type = MyType {
func: None,
};
my_type.set_func(|| -> HashSet<Romans> {
HashSet::from(my_list
.iter()
.map(|item| {
match item {
Numbers::One => Romans::I,
Numbers::Two => Romans::II,
Numbers::Three => Romans::III,
}
})
.collect()
)
});
my_type.run();
}
When I try to compile, I get the following error:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:27:23
|
27 | let result = (self.func.unwrap())();
| ^^^^^^^^^ cannot move out of borrowed content
error: aborting due to previous error
I don't quite understand what is being moved out. Is it a hidden self? The resulting HashSet? or maybe the values inside the set?
What am I doing wrong?
The trouble you're having is that calling unwrap on an Option will consume it--it takes self as an argument. Inside run(), your MyType only has a &mut self reference to itself, so it cannot take ownership of its field.
The solution is to take mutable reference to the stored function instead:
pub fn run(&mut self) {
if let Some(func) = &mut self.func {
let result = func();
if result.contains(&Romans::I) {
println!("Roman one!");
}
}
}

Resources