Ownership
At one point in time, only one variable may own a piece of data. If a given variable holds data on a stack, the data is just copied:
In the case of heap data, only the pointer is copied:
Unique to Rust, the a
variable becomes invalid when the code above gets
executed. If we try to access it, it will result in a compilation error. Thanks
to it, during runtime Rust will not try to drop/free this memory space twice, which
would be wrong. It is called a move. a
’s contents get moved to b
.
Passing a value to a function also causes a move!
A function may also move ownership by returning a value. Then, the calling function’s scope owns the variable.
References
Sometimes we want to pass a value to a function, but also to continue to use it in the calling function. We could make the called function return the passed-in value, but that would be a weird workaround, especially if that function is supposed to return some other data as well. References come to the rescue.
Creating a reference is called borrowing.
References are immutable by default. We can change that:
Both the s
variable and the some_string
reference need to use the mut
keyword to allow mutations of the value.
With Rust, it’s impossible to have dangling pointers. Rust will complain about such issues at compile time.
Dereferencing
Sometimes we might need to obtain an actual value that the reference is pointing to. We can do that with the dereferencing operator:
Slices
Slice is a part of some collection. It is a pointer to some index of that collection and a count of elements starting from that index.
String Slice
Sometimes we need to “extract” a part of a string. Instead of creating a totally new string, disconnected from the original one, we can use a String Slice.
slice
contains the pointer to the first character of the slice, and the length
of the slice. Additionally, the slice has a reference to s
(?), so s
cannot
be mutated while slice
is still in use.
A reference to a string is treated as a string slice.