I was forced to understand and study memory management, life cycle management, etc.

Contrast with C/C++ and Python, by the way.

C/C++

C/C++ is a familiar language. Assignments are shallow copies by default. That is, for non-pointer and reference types, elements are copied as expected. But for references and Pointers, only a copy of the pointing relationship is copied, and there is still only one target memory.

This is why destructors of C++ classes often deal with pointer members pointing to memory. It’s also why container types often need to store Pointers to objects rather than the objects themselves.

python

Python’s memory management is GC (garbage collection), so assignments, parameter passing, and so on are all referenced. This approach works perfectly with GC, but can cause a lot of problems if you don’t understand it.

For example, the more classic problem is the difference in the results of operations on mutable and immutable elements when they are “modified”.

    a = 13
    b = a
    b += 1
    print(a) # 13
    print(b) # 14
    
    a = [1.2]
    b = a
    a.append(3)
    print(a) # [1, 2, 3]
    print(b) # [1, 2, 3]
Copy the code

Further down the List if you have mutable and immutable, you get different results

    a = ['a'[1.2.3]]
    b = list(a) // shallow copy, a and B are different, but the elements inside are all references to the same object A [0] = 'b'
    print(a) // ['b'[1.2.3]]
    print(b) // ['a'[1.2.3]]

    a[1].append(4)
    print(a) // ['b'[1.2.3.4]]
    print(b) // ['a'[1.2.3.4]]
Copy the code

A more insidious scenario is when a function’s parameter and argument are passed, and the parameter is actually a reference to the argument

def add_two_num(a, b) :
    a += b
    return a

if __name__ == '__main__':
    a = 3
    b = 4
    print(add_two_num(a, b))  # 7
    print(a, b) Number 3, 4, A doesn't change

    a = [1.2]
    b = [3.4]
    print(add_two_num(a, b))  # [1, 2, 3, 4]
    print(a, b) # [1, 2, 3, 4] a changed

    a = (1.2)
    b = (3.4)
    print(add_two_num(a, b))  # (1, 2, 3, 4)
    print(a, b) # (1, 2) (3, 4) A doesn't change
Copy the code

Rust

Rust’s memory management uses the advanced game of RAII (Resource Acquisition Is Initialization) + lifecycle of C++, which makes assignment unique.

In principle, assignment to Rust is a transfer of ownership by default, that is, ownership of the memory corresponding to an rvalue is transferred to an lvalue while the rvalue is uninitialized.

For basic data types (integer/floating-point/STR), assignment is copy because copy and Clone traits are implemented by default.

fn main() {
    let a = 1;
    let b = a;
    println!("{}", a);
    println!("{}", b);

    let a = String::from("String");
    let b = a; // String does not implement copy trait, so move is an ownership transfer
    println!("{}", a); // ^ value borrowed here after move
    println!("{}", b);
}
Copy the code

conclusion

Memory management is at the root of the differences in assignment between languages, so it’s a priority to figure out. Second, the management of assignment or ownership, which involves program efficiency, correctness, etc., needs to be careful.

Practice, practice, practice, practice, practice, practice, practice, practice, practice, practice.