A language I want to learn but really have no reason to.

Note

Until Jan 5th 2026 where I enrolled in ECE459.

Ownership

Uses an ownership type system to achieve automatic memory management without a garbage collector.

In essence, allocated memory can be cleaned up when no one needs it anymore. Ownership imposes restrictions on how you write your code. The main advantage here is that you can’t mess up and leave dangling references.

Rules

  • Every value has an owner
  • There can only be one owner at a time
  • When the owner goes out of scope, the value is dropped

There are move and copy semantics:

  • For basic primitives, it is easier to just copy over a values if we do something like x=y
  • But for things with a heap component, we pass ownership, and the previous variable goes out of scope
    • We can also clone something to explicitly copy it

Lifetimes

The compiler can make a determination about how long a piece of data will live. The compiler makes decisions based on local information. To get something that throws a lifetime error to compile, you need to specify a lifetime using an annotation, however, this doesn’t actually change how long the references live, just describes the relationships between lifetimes.

fn longest<'a>(...){...}

We define a lifetime annotation using that ' syntax above. You can make the lifetime immortal using ' static. You can use this to bandaid compiler errors. Memory that is around forever but is no longer useful is fundamentally like a memory leak.

There exists the keyword unsafe which you might need to write low-level code. But, by using this keyword, you get the errors that Rust tries to avoid.

Unsafe

Here, you can:

  • Call an unsafe function
  • Access or modify a mutable static variable
  • Implement an unsafe trait
  • Access the fields of a union
  • Dereference a raw pointer

You can also specify unsafe by putting it in a function signature. A trait can also be unsafe. We need to wrap unsafe function calls in an unsafe block.

You can also make global mutable variables but these need to be unsafe.

A union is a struct in declaration but all its fields exist in the same memory superimposed over one another (these can be different types).

Raw Pointers

You can create raw pointers anywhere but you can only dereference them in an unsafe block. You get errors when you use them, not create them.

Borrowing

A consequence of ownership is borrowing. This is where you need data for something and then promise to give it back. The Rust borrow checker produces compile-time errors if it thinks a borrow is unsafe. You pass a reference to borrow and this reference is immutable. You otherwise need to pass a &mut if you want the reference to be mutable.

Unwrapping

A lot of functions we use return a Return type. This will return an ok, or an err. We can unwrap the result type, or expect it. Use expect() instead of unwrap() if an error is reasonably foreseeable.

Traits

Traits are Rusts version of multiple inheritance. These are like interfaces. You can only define traits on your own types, you can also provide a default implementation. Important traits include…

Iterator

If you put this on a collection, you can iterate through it.

Send

This is required to transfer ownership between threads.

Sync

This means this type is thread-safe. It can be referenced from multiple threads without an issue.

Quirks

  • Semicolons end expressions, you can return from a function by stating the value without a semicolon
  • Variables are by default immutable, you need to specifically mention that you want it to be mut
  • Constant are immutable and immortal and are valid for the entire scope they are defined in
  • static variables are global variables
  • Rust uses shadowing to redefine a variable under a new type to avoid the problem where you define a variable to read raw data input and then parse it into another, we can now use the same name
  • Slices (contiguous subsets) are references, the entire is protected if we have a slice of an array

Pitfalls

  • Using static lifetimes
  • Overuse of clone()
  • Array indexing overhead vs iterator
  • Unbuffered IO
  • resize() on a vector
  • Unguarded unwrap() everywhere
  • Vibe coding