I am beginner in rust and i have some misunderstand and wondering, about mut and immutable so i decided to shared them to explain as a rust beginner what the questions i have, what feel not intuitive for me and try to understand the logic behind. I welcome any explanations and discussions on what you feeling about
In brief my questions are
-
if mutable is a status of variable in a specific scope, so the decided on this status will be only when you receiving variable into a scope or change it in a middle scope not in return value,
if not what the exact definition of the mutable in rust ? and why you need to decided in a function if the variable return as mut /immut, who that use in the function get the decision according its scoop definition -
Rust prevent reference of more then one mutable to one variable in a scope. what is the reason ? if the reason (as i assumed) is you can to change the reference of anther variable, what about relative reference to the struct root in rust to solve that problem there is something like that in rust ? if i understand right the problem in these scenario is safety not a wrong pattern (some time for clear code reasons you holds some variables of the same structs) there is a way to solve only the safety issue
(Sorry about my English)
thanks in advance
Questions to steps , each step is a block of code with notes as a comment
Step 1
fn main() {
// Create mutable person in this scope,
// assumptions:
// 1. By write let mut before the variable name 'p' it become mutable.
// 2. You can change the p and its fields so mutable related to the entire struct.
// 3. mut is status of a variable in specific scope.
let mut p = Person {
name: "Moshe".into(),
age: 29,
};
// I can change the name, p is mutable
p.name = "New Name".into();
// I revive name and age as mut because i want to change them
// (get_name for me it's a black box that return some ref to 'name', also i now that it not change my struct because it get self as immutable)
// the assumption 1 as before (by write let mut, name/age become mutable)
let mut name = p.get_name();
let mut age = p.get_age();
// lets change the name
// Oops i got a error: cannot assign to immutable borrowed content `*name / age`
// but i receive them as mutable as i receive p.
*name = "Bob".into();
*age = 35;
println!("Hi i am {} {} yours old", name, age);
println!("Hi i am {} {} yours old", p.name, p.age);
}
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
impl Person {
fn get_name(&self) -> &String {
// self is immutable because there is no change in the self > make sense
&self.name
}
fn get_age(&self) -> &u32 {
// the same as get_name
&self.age
}
}
Step 2
So i fixed the previous error by creating to anther functions that get self and return its field as mutable
fn main() {
// Create mutable person in this scope
let mut p = Person {
name: "Moshe".into(),
age: 29,
};
// the solution
// so the assumption as before (by write let mut, name/age become mutable) not right when you turn to method,
// so the mut is not only status of a variable in specific scope it more like a type / reference
let name = p.get_name_mut();
// lets change the name. now it works
*name = "Bob".into();
// error cannot borrow `p` as mutable more than once at a time
// that means when holding mutable referance to a variable (struct Person in this case) you can't hold more then once.
// It can try to infer why ( not changing the ref of the name by p.name )
let age = p.get_age_mut();
// I got a error:
// cannot assign to immutable borrowed content `*name / age`
// *age = 35;
println!("Hi i am {} {} yours old", name, age);
}
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
impl Person {
fn get_name_mut(&mut self) -> &mut String {
// I don't want self as mutable becuse no change in self ocured here,
// but rust force me if i want to return mutable (but according to assumption 3 (mut is status of a variable in specific scope),
// why i need to decided how name will returned (mut /immut) this is not a part of the function business)
&mut self.name
}
fn get_age_mut(&mut self) -> &mut u32 {
// the same as get_name_mut
&mut self.age
}
}
Step 3
To solve the previous error i wrapped the name and age to a internal scope
fn main() {
// Create mutable person in this scope
let mut p = Person {
name: "Moshe".into(),
age: 29,
};
let name;
let age;
// the solution to the previous errors
// wrap the name and age to a internal scope
{
let _name = p.get_name_mut();
// lets change the name. now it works
*_name = "Bob".into();
name = &*_name;
// i can't try to change name because now it immutable
// *name = "Not will work";
}
{
// now we got a error here: cannot borrow `p` as mutable more than once at a time
// OK one is mutable p, but where is the scones? (name is immutable)
// probably the reason is because there is mutable and immutableto the same struct
// but the question what the right pattern for these scenarios ?
let _age = p.get_age_mut();
*_age = 35;
age = &*_age;
}
println!("Hi i am {} {} yours old", name, age);
}
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
impl Person {
fn get_name_mut(&mut self) -> &mut String {
// I don't want self as mutable because no change in self occurred here,
// but rust force me if i want to return mutable (but according to assumption 3,
// why i need to decided how name will returned (mut /immut) this is not a part of the function business)
&mut self.name
}
fn get_age_mut(&mut self) -> &mut u32 {
// the same as get_name_mut
&mut self.age
}
}