PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Sunday, July 10, 2022

[FIXED] How do I get a mutable reference out of a vector?

 July 10, 2022     borrow-checker, reference, rust, self     No comments   

Issue

Both the run and send methods need a self object, and the send function also needs a mutable Packet reference:

struct Package {
    id: u32,
}

impl Package {
    fn new(id: u32) -> Package {
        Package { id }
    }
}

struct Manager {
    packages: Vec<Package>,
}

impl Manager {
    fn new() -> Manager {
        Manager {
            packages: vec![
                Package::new(1),
                Package::new(2),
                Package::new(3),
                Package::new(4),
            ],
        }
    }
    fn run(&mut self) {
        for package in self.packages.iter_mut() {
            if package.id == 1 {
                self.send(package);
            }
            println!("{}", package.id);
        }
    }
    fn send(&self, package: &mut Package) {
        package.id = 23;
    }
}

fn main() {
    let manager = Manager::new();
    manager.run();
}
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src/main.rs:29:17
   |
27 |         for package in self.packages.iter_mut() {
   |                        ------------------------
   |                        |
   |                        mutable borrow occurs here
   |                        mutable borrow later used here
28 |             if package.id == 1 {
29 |                 self.send(package);
   |                 ^^^^ immutable borrow occurs here

error[E0596]: cannot borrow `manager` as mutable, as it is not declared as mutable
  --> src/main.rs:41:5
   |
40 |     let manager = Manager::new();
   |         ------- help: consider changing this to be mutable: `mut manager`
41 |     manager.run();
   |     ^^^^^^^ cannot borrow as mutable

How I can refactor these two functions to get it working?

I don't want to copy the packet, since that would lead to lots of trouble with my original code.


Solution

Option 1: don't accept &self in send(). Just let it take the things from self that it needs, such as &mut Package and possibly other fields:

// call it with Self::send(package)
fn send(package: &mut Package) {
    package.id = 23;
}

Option 2: accept a package index instead of &mut Package:

fn run(&mut self) {
    for package_idx in 0..self.packages.len() {
        if self.packages[package_idx].id == 1 {
            self.send(package_idx);
        }
        println!("{}", self.packages[package_idx].id);
    }
}

fn send(&mut self, package_idx: usize) {
    self.packages[package_idx].id = 23;
}

Option 3: use interior mutability.

struct Manager {
    packages: Vec<RefCell<Package>>,
}

impl Manager {
    fn new() -> Manager { ... }

    fn run(&mut self) {
        for package in &self.packages {
            if package.borrow().id == 1 {
                self.send(package);
            }
            println!("{}", package.borrow().id);
        }
    }
    fn send(&self, package: &RefCell<Package>) {
        let package = package.borrow_mut();
        package.id = 23;
    }
}

Which option is right for you depends on your use case. All else being equal, I'd prefer option 1, then 2, then 3.



Answered By - user4815162342
Answer Checked By - Marilyn (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing