Pass by reference

Hello

I'm trying to pass a parameter by reference like in this C++ code:

#include <iostream>
#include <algorithm>
#include <string>

enum myEnum {
    Do_Something,
    Do_Nothing,
};

class Calculator {
    public:
    void calculate(float &a, std::string &b, myEnum &c, std::string& d) {
        //Base-condition:
        //if b is empty, return
        if (b == "") return;

        //First character from string b
        char x = b[0];
       
        //If enum is not yet set, set
        if (c == NULL) {
            c = myEnum::Do_Something;
        }

        //Add to string d if allowed by myEnum
        if (c == myEnum::Do_Something) {
            d += x;
        }

        //Remove from b
        b.erase(0, 1);

        //Increment a by one
        a++;

        //OUTPUT
        std::cout  
            << "a: " << a << std::endl
            << "b: " << b << std::endl
            << "d: " << d << std::endl
            << std::endl;
    }
};

int main() {
    std::string myStr = "abcdefghijk";
    
    ///////////
    float a;
    myEnum c;
    std::string d;

    Calculator calc;
    calc.calculate(a, myStr, c, d);
    calc.calculate(a, myStr, c, d);
    calc.calculate(a, myStr, c, d);
}

I'm trying to pass a variable to the function by reference, alter that variable in the function, so I can access the new value after the function is executed. My target is to make some kind of recursive function later.

Rust-code:

enum myEnum {
    DoSomething,
    DoNothing,
}

struct Calculator;
impl Calculator {
    pub fn calculate(&self, a: &mut f32, b: &mut String, c: &mut Option<myEnum>, d: &mut String) {
        //Base-condition:
        //if b is empty, return
        if b == "" {
            ()
        }
        
        //First character from string b
        let x = b.chars().nth(0).unwrap();
        
        //If enum is not yet set, set
        if c.is_none() {
            c = &mut Some(myEnum::DoSomething);
        }
        
        //Add to string d if allowed by myEnum
        if !c.is_none() {
            d.push_str(&x.to_string());
        } else {
            d = &mut "".to_string();
        }
        
        //Remove from b
        b = &mut b[1..b.len()].to_string();
        
        //Increment by one
        //a = a + 1.00;
        
        //Output:
        println!("a: {}\nb: {}\nd: {}", a, b, d);
    }
}

fn main() {
    let myStr = "abcdefghijk";
    
    let a = 0.00;
    let c : Option<myEnum> = None;
    let d : String = "".to_string();
    
    let calc = Calculator {};
    calc.calculate(&mut a, &mut myStr.to_string(), &mut c, &mut d);
}

Playground.

Errors:

error[E0384]: cannot assign to immutable argument `c`
  --> src/main.rs:20:13
   |
8  |     pub fn calculate(&self, a: &mut f32, b: &mut String, c: &mut Option<myEnum>, d: &mut String) {
   |                                                          - help: make this binding mutable: `mut c`
...
20 |             c = &mut Some(myEnum::DoSomething);
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign to immutable argument

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:20:22
   |
8  |     pub fn calculate(&self, a: &mut f32, b: &mut String, c: &mut Option<myEnum>, d: &mut String) {
   |                                                             - let's call the lifetime of this reference `'1`
...
20 |             c = &mut Some(myEnum::DoSomething);
   |             ---------^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
   |             |        |
   |             |        creates a temporary which is freed while still in use
   |             assignment requires that borrow lasts for `'1`

error[E0384]: cannot assign to immutable argument `d`
  --> src/main.rs:27:13
   |
8  |     pub fn calculate(&self, a: &mut f32, b: &mut String, c: &mut Option<myEnum>, d: &mut String) {
   |                                                                                  - help: make this binding mutable: `mut d`
...
27 |             d = &mut "".to_string();
   |             ^^^^^^^^^^^^^^^^^^^^^^^ cannot assign to immutable argument

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:27:22
   |
8  |     pub fn calculate(&self, a: &mut f32, b: &mut String, c: &mut Option<myEnum>, d: &mut String) {
   |                                                                                     - let's call the lifetime of this reference `'2`
...
27 |             d = &mut "".to_string();
   |             ---------^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
   |             |        |
   |             |        creates a temporary which is freed while still in use
   |             assignment requires that borrow lasts for `'2`

error[E0384]: cannot assign to immutable argument `b`
  --> src/main.rs:31:9
   |
8  |     pub fn calculate(&self, a: &mut f32, b: &mut String, c: &mut Option<myEnum>, d: &mut String) {
   |                                          - help: make this binding mutable: `mut b`
...
31 |         b = &mut b[1..b.len()].to_string();
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign to immutable argument

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:31:18
   |
8  |     pub fn calculate(&self, a: &mut f32, b: &mut String, c: &mut Option<myEnum>, d: &mut String) {
   |                                             - let's call the lifetime of this reference `'3`
...
31 |         b = &mut b[1..b.len()].to_string();
   |         ---------^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
   |         |        |
   |         |        creates a temporary which is freed while still in use
   |         assignment requires that borrow lasts for `'3`

error[E0502]: cannot borrow `*b` as immutable because it is also borrowed as mutable
  --> src/main.rs:31:23
   |
31 |         b = &mut b[1..b.len()].to_string();
   |                  -----^-------
   |                  |    |
   |                  |    immutable borrow occurs here
   |                  mutable borrow occurs here
   |                  mutable borrow later used here

error[E0596]: cannot borrow `a` as mutable, as it is not declared as mutable
  --> src/main.rs:49:20
   |
44 |     let a = 0.00;
   |         - help: consider changing this to be mutable: `mut a`
...
49 |     calc.calculate(&mut a, &mut myStr.to_string(), &mut c, &mut d);
   |                    ^^^^^^ cannot borrow as mutable

error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
  --> src/main.rs:49:52
   |
45 |     let c : Option<myEnum> = None;
   |         - help: consider changing this to be mutable: `mut c`
...
49 |     calc.calculate(&mut a, &mut myStr.to_string(), &mut c, &mut d);
   |                                                    ^^^^^^ cannot borrow as mutable

error[E0596]: cannot borrow `d` as mutable, as it is not declared as mutable
  --> src/main.rs:49:60
   |
46 |     let d : String = "".to_string();
   |         - help: consider changing this to be mutable: `mut d`
...
49 |     calc.calculate(&mut a, &mut myStr.to_string(), &mut c, &mut d);
   |                                                            ^^^^^^ cannot borrow as mutable

error: aborting due to 10 previous errors

Some errors have detailed explanations: E0384, E0502, E0596, E0716.
For more information about an error, try `rustc --explain E0384`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

So how do I convert that working C++ code to Rust? Thanks!

The assignment to pointee syntax is of course *p = x and not p = &mut x

3 Likes

This is no-op. The function returns the last expr of its body by default. and this if-expr is definitely not a last one. If you want to return early without packing everything in the body with single if-expr, use return expr.

if b.is_empty() {
    return
}
4 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.