30 Days of Rust - Day 16
Tags: rust, learning, beginners
Published: 2023-05-10 22:16:42

Evening all,
Today was a hectic one. I'm jetting off for my first summer(ish) vacation next week so I have to clean up a few *dangling* ends at work. Today's post will focus on Rust's ownership concept and its rules. We'll also look at `String` again and tie that in with ownership.

## Yesterday's questions answered
- By assigning something a `'static` lifetime value, you tell rust that the value should live for the entirety of program's duration.

## Today's open questions
- Do Rust's reference rules apply to slices?

## Primitive types as binary code
The Rust book introduces its topic of ownership through the lens of a computer's available memory, which is split between a compile-time stack and a runtime heap. Non-primitive data types stored on the heap get allocated at runtime, but the pointers to the heap are added to the stack at compile-time.

What I find conceptually interesting, however, is how primitive types (e.g.  string or boolean literals, `i32` or `f64`) as well as other things (functions, structs) on the stack are baked into the binary produced by the Rust compiler. In this sense they are just slices in your binary!

## Move variable, get out the way
So managing the stack and heap is not something novel to Rust. However, it's approach to managing data *on the heap* is novel and is what I've been referring to as *ownership*. In an [earlier blog post](https://dev.to/johnnylarner/30-days-of-rust-day-4-120n) I summarised the 3 holy rules of the ownership. 

Rule number two states that a value on the heap can only have one owner at a time. When we bind an existing value to a new variable, we actually *moving* it into a new owner. In Python, this is somewhat related to the concept of mutability and the differentiation between pass-by-value and pass-by-reference. The key difference is that Rust will drop the old variable whenever you *move* it into a new reference. To copy value you'd have to call `clone` on it before hand. 

Remember this behaviour only concerns values on the heap. Stuff on the stack can be copied easily, no questions asked.

## Gimme a reference
Another way to *move* a value is to pass it into another scope (typically using a function). This may seem reasonable at first glance, but you quickly realise that as soon as you want to return something merely *derived* from a function's arguments, you end up with very messy code.  Compare these two functions:
```rust
fn calculate_length_owned(s: String) -> (String, usize) {
	let length = s.len();
	(s, length)
}

fn calculate_length_borrowed(s: &String) -> usize {
	s.len()
}
```

The Rust solution here is to create a reference to the value. This means that the value can be *borrowed* via its reference. If the value and its reference are declared mutable, changes to borrowed values can be made too.

References carry their own set of rules. These can be summarised as follows:
- A value can have any number of *immutable* references
- But a value may only have one *active* *mutable* reference at any given point
- And whenever there is an *active mutable* reference, there cannot be any *immutable* references
- Attempts to leave dangling references will leave you at odds with the compiler!

You can take a moment to think about the kind of side-effects (think, also, race conditions) which effectively become impossible with these rules enforced by the compiler.

## Slices as view
Both strings and arrays can be sliced in Rust. The syntax is very similar to Python, though the colon is replaced by two dots: `&my_string[0..10]`. The view a slice gives on either a `String` or string literal is bound to the value. Thus, mutating the value will affect the slice.