Passing Data in Move: Value vs. Reference
Move uses pass-by-value for copies and pass-by-reference (& for reading, &mut for modifying) to data handling.
For the latest RPC URL, please refer to the Supra Network Information page.
pass-by-value & pass-by-reference
In Move, when you pass a simple value as u64 to a function, you might be making a copy of it. This is called pass-by-value, for example:
fun add_one(value: u64) {
// This doesn't change the original value!
value = value + 1;
}
fun call_add_one() {
let value = 10;
// This is wrong as it makes a copy of value!
add_one(value);
// This will error out as the value is still 10!
assert!(value == 11, 0);
}So how do we modify the original value?
We need to pass a mut reference (&mut) to the value instead of the value itself. This is called pass-by-reference. This is similar to how you pass a pointer to a value in C/C++ or Rust.
There are two types of references in Move: references (&) and mutable references (&mut). The immutable reference (&) is often used to pass a value such as a vector to a function that only intends to read data instead of writing it. A function that takes a reference needs to explicitly declare:
// get_first_element takes a reference to a vector and returns the first element.
fun get_first_element(values: &vector<u64>): u64 {
// vector::borrow also takes a vector reference and returns a reference to the value.
// * is needed here to dereference the value and make a copy of it to return.
*vector::borrow(values, 0)
}You can also pass a reference to a struct and modify it:
struct Balance {
value: u64,
}
// This would fail if the function takes &Balance instead of &mut Balance.
fun double_balance(balance: &mut Balance): u64 {
balance.value = balance.value * 2;
balance.value
}Now, write a function in dinosaur_nest that returns the Gendna of the first Dinosaur in the DinosaurSwarm. Don’t forget the “acquires” declaration!
module 0xcafe::dinosaur_nest {
use std::vector;
struct DinosaurGendna has key {
gendna_digits: u64,
gendna_modulus: u256,
}
struct Dinosaur has store {
gendna: u64,
}
struct DinosaurSwarm has key {
dinosaurs: vector<Dinosaur>,
}
fun init_module(cafe_signer: &signer) {
let gendna_digits = 10;
// 10^10. Move has no exponent operator, so the value is written out.
let gendna_modulus = 10000000000;
move_to(cafe_signer, DinosaurGendna {
gendna_digits: gendna_digits,
gendna_modulus: (gendna_modulus as u256),
});
move_to(cafe_signer, DinosaurSwarm {
dinosaurs: vector[],
});
}
public fun spawn_dinosaur(gendna: u64): Dinosaur {
Dinosaur {
gendna: gendna,
}
}
public fun get_gendna_digits(): u64 acquires DinosaurGendna {
borrow_global<DinosaurGendna>(@0xcafe).gendna_digits
}
public fun set_gendna_digits(new_gendna_digits: u64) acquires DinosaurGendna {
let dinosaur_gendna = borrow_global_mut<DinosaurGendna>(@0xcafe);
dinosaur_gendna.gendna_digits = new_gendna_digits;
}
public fun get_first_dinosaur_gendna(): u64 acquires DinosaurSwarm {
let dinosaur_swarm = borrow_global<DinosaurSwarm>(@0xcafe);
let first_dinosaur = vector::borrow(&dinosaur_swarm.dinosaurs, 0);
first_dinosaur.gendna
}
}