How to use a function that returns and modifies its input value

#1

Hi All,

This may be trivial but I couldn’t find any examples.

fn function_one(list_one : HashMap<String, u64>) -> (Vec<String>,Vec<String>){
let mut a : Vec<String> = Vec::new();
let mut b : Vec<String> = Vec::new();
//read list_one and do something
(a,b)
    }
fn function_two(a: Vec<String> ,b : Vec<String> , mut list_one : Vec<String> , mut map_one : HashMap<u64, Vec<u64>> ) -> (Vec<String>,HashMap<u64, Vec<u64>>){

// do something
(list_one, map_one)
}

fn main{
let mut list_one : Vec<String> = Vec::new();
let mut map_one : HashMap<u64, Vec<u64>> = HashMap::new();

let (a,b) = function_one(list_one); // reading not modifying
(list_one,map_one) = function_two(a,b, &mut list_one, &mut map_one); // How does this part work? 
}

How do I get this work in Rust?

0 Likes

#2

A few errors:

  1. You need to add parenthesis to main's parameter declaration.
  2. You can’t have an expression like (a, b) = returns_a_tuple() on its own. You need to use a new let statement, or some kind of temporary variable, or even a temporary variable in a new scope so as to drop it when necessary.
  3. function_2 takes a Vec by value, not by reference and therefore trying to call it like so wouldn’t work:
function_two(a, b, &mut c, &mut d)
  • This can be fixed by changing the way that you call the function or by changing the declaration of said function
//Either will work:
fn function_two(
    a: Vec<String>,
    b: Vec<String>,
    list_one: &mut Vec<String>,
    map_one: &mut HashMap<u64, Vec<u64>>) -> (Vec<String>, HashMap<u64, Vec<u64>>) {

// do something
    (list_one, map_one)
}
//OR
let (a, b) = function_one(list_one); 
let (list_one, map_one) = function_two(a, b, list_one, map_one);
  1. But unfortunately this won’t work either way! function_one takes a HashMap<String, u64> by value, and will therefore take ownership of it, therefore invalidating it for further use. Either use a reference, like shown in the previous example, or take the sub optimal route of storing a clone in a temporary variable. Note that this is sub optimal because .clone() will copy every one of the Vec's elements. This is even worse, considering that it contains Strings and will therefore require nested calls to buffer copies.
0 Likes

#3

Thanks for the reply. If I change like this, is that ok?

fn function_one(&mut list_one : HashMap<String, u64>) -> (Vec<String>,Vec<String>){
let mut a : Vec<String> = Vec::new();
let mut b : Vec<String> = Vec::new();
//read list_one and do something
(a,b)
}
fn function_two(a: Vec<String> ,b : Vec<String> , &mut list_one : Vec<String> , &mut map_one : HashMap<u64, Vec<u64>> ) -> (Vec<String>,HashMap<u64, Vec<u64>>){

// do something
(list_one, map_one)
}

fn main{
let mut list_one : Vec<String> = Vec::new();
let mut map_one : HashMap<u64, Vec<u64>> = HashMap::new();

let (a,b) = function_one(&mut list_one); // reading not modifying
let (list_one,map_one) = function_two(a,b, &mut list_one, &mut map_one); // How does this part work? 
}
0 Likes

#4

The argument syntax is name: type (or strictly speaking, pattern: type) so for mutable Vec reference it’s list_one: &mut Vec<String>.

The mut name: type syntax means you can assign something else to name, but the type is still the same and it’s not made mutable.

1 Like

#5

Thanks @kornel. I have one more question, if I put let(list_one,map_one) , would the values get reset or updated?

0 Likes

#6

Also, in your function you don’t really need to have a mutable reference as your comment suggests that you are just reading from it and not actually modifying it.

fn foo(data: &Bar)

Would work, and instead of calling it like so:

foo(&mut my_bar)

you can call it like so:

foo(&my_bar)
0 Likes

#7

They would be reset:

let a = 2;
let a = 3;
//Any use of `a` from here on out will have the value 3

In the second time we declare a, we just so happen to name it the same as the first a, and will therefore end up with the second a taking precedence naming-wise.

0 Likes

#8

So no way I can get the function to keep updating the input value. So what is the way out? Do I need to use mutex or something?

0 Likes

#9

If you want a function to take a value and not consume it and be able to modify it then use a mutable reference (&mut T)

0 Likes

#10

Yes. I understand that and use it. But how that function returns the same value which itself modifies it in a for loop? Something like

for k in 1..10
{
let (list_one,map_one) = function_two(a,b, &amp;mut list_one, &amp;mut map_one); // I want the list_one to updated on every iteration. 
}
0 Likes

#11

Well, since it is written how it is you can do something like this:

let (mut list_one, mut map_one) = (Vec::new(), HashMap::new());
for _ in 1..10 {
    let temp = function_two(a, b, &mut list_one, &mut map_one);
    list_one = temp.0;
    map_one = temp.1;
}

and just make it take the values by mutable reference.

0 Likes

#12

Thanks for your help. I will try and update. Thanks a lot.

0 Likes