References

Languages like Java, C#, Python and PHP all use garbage collection to detect and free memory containing unused functions and variables, meaning an extra program must be running at all times during execution to perform this task. This can lead to slower execution times and less time-efficient and space-efficient programs.

Languages like C have no garbage collector, meaning they are faster in execution, but may require the programmer to handle memory manually, with minor mistakes in memory management leading to fatal errors that are difficult to predict or notice.

Fatal errors involving memory can also cause undefined behaviour, a set of unpredictable events that occur as a result of the runtime executing broken, residual instructions (which could cause anything from file corruption to fatal crashes of the entire operating system).

Rust strikes a middle ground between these two execution models:

In the above animation, some_func() is some function that takes a String struct as an argument, but doesn't return the same struct.

This strict system of ownership means that all values stored in memory can be tightly controlled and monitored, making Rust programs much more memory-safe than C programs, without the need for a resource-costly garbage collector.

However, there are inevitably going to be situations where a single variable needs to be accessed by many different parts of a Rust program multiple times. In order to allow this to happen, references to variables can be used in place of the variables themselves:

References to variables, and the definition of the types of these variable references, are denoted with an ampersand (&).


    

When a reference to a variable is passed to a function as an argument, that function borrows the variable for the duration of its execution, through the reference to it, meaning that ownership of the variable does not change.

Note, in the above example, how the String variable s was borrowed multiple times in the main function, but only borrowed mutably once. This is another immensely important ownership rule that helps to make memory safety guarantees.

If multiple mutable borrows could be made at once, race conditions (situations where the same variable is edited or overwritten by multiple processes, leading to unexpected behaviour) would occur.

However, most primitive types in Rust, such as integers, floating-point numbers, booleans, and characters, aren't moved when they are used in a function or assigned to another variable.

Since they take up very small, fixed amounts of memory space, they have a trait called Copy, which allows them to be simply copied, instead of moved, to the variable or function they might be used with. More technical details of why primitive types behave this way can be found on the next page.

Exercise:
Fix the ownership-related compile error with the following code: