- Any function whose name ends with a
!
is a macro. Macros and functions are different in how they operate. For example
- Rust macros are executed at compile-time and are hygienic in compilation and execution
- Rust is a statically-typed language
- Rust does not have a garbage collector
- If you see a .pdb filename extension, that is a debugging information file
- Crates are packages of codes. I think of them as libraries that go under the
[dependencies]
section in cargo.toml - Source code files go into the src subdirectory. Everything else goes into the parent directory
- When building a cargo directory, the executable file will be found in the default debug build folder (/target/debug/)
Note
When executing a .exe file in PowerShell, type
./exe_name
-
When accessing invalid or non-extant elements of an array, Rust will not execute the code and spit garbage values; it will stop compiling and will throw an error. This is a key part of Rust’s memory safety principles
-
let
defines an immutable variable by default. To declare a mutable variable, uselet mut
-
To declare a variable along with its type, use type annotations
Difference between mut
and shadowing
mut
allows the variable’s contents to be changed but the type cannot be mutated. In shadowing, however, that is possible because a new variable is being created from scratch- Shadowing eliminates the difficulty of naming variables appropriate to the use case. This is not possible using
mut
Statements and Expressions
-
A statement does not evaluate to a value. It just performs some process
let x = 5;
is a statement.let x = (y = 6);
will return an error because it’s a statement
-
An expression evaluates to a value
-
Expressions do not include ending semicolons. Including one turns an expression into a statement
-
Return statements are expressions and are not named
-
Conditions associated with
if
statements are called arms -
Rust will not automatically convert non-Boolean types to
bool
, unlike Python -
References are immutable by default
-
Libraries are called crates in Rust
-
Find crates and Rust open-source projects in https://crates.io/
Cargo.lock The Cargo.lock file is created to ensure reproducible builds. When you build a program with external dependencies (crates) for the first time after specifying the dependency details in Cargo.toml, it will download the dependencies that match the criteria for the project and use them. It then creates a Cargo.lock file with the version numbers of the dependencies it’s using. In the future, rebuilds will be fast because Rust can directly reference Cargo.lock
- Cargo.lock is checked into source control → easy for portable rebuilds
To convert one type to another, do this
match
is much like switch
in C++ and allows for strong pattern matching
trim()
removes all whitespaces and newlines. Useful for when you’re converting a string to a number, for example
parse()
does the type conversion
Ok(num) => num
is when the conversion is valid and the converted data is put in a num
buffer (you don’t have to separately declare num
). If there was an error, Err(_)
will capture any error (_
is a catchall wildcard for any and all errors) and just continue code execution, skipping the conversion
Ownership
Source: Ownership - Rust Programming Book
-
[I] This could go into a different note - Why did I choose Rust?
-
Set of rules that govern how Rust uses memory
-
Rust compiler checks for certain ownership rules. If any of those rules are violated, the program won’t compile
-
Ownership is to manage heap memory
- Heap memory is slower than stack allocation, and can be chaotic
Ownership rules
- Each value has an owner
- There can only be one owner at a time
- When the owner goes out of scope, the value will be dropped
- [!] Remember this!
String
is a variable type that stores data in the heap. It can be mutated
String literals cannot be mutated but String
data can
When a variable goes out of scope, Rust automatically frees the memory it has occupied - 3rd ownership rule. The drop
function is auto-called
- [n] Resource Acquisition Is Initialization (RAII)
Variable Scope Exit Error
error[E0382]: borrow of moved value
… — move occurs because … which does not implement the ‘Copy’ trait
…
= note: this error originates in the macro $crate::format_args_nl
which comes from the expansion of the macro println
(in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
For more information about this error, try rustc --explain E0382
.
This compilation error indicates that a variable that exited the scope can't be used because Rust automatically frees its memory upon scope expiry
Rust does not perform a deep copy by default. To do one, use clone()
- If you see
clone()
being used, there’s a chance some arbitrary code may be executed. Sounds fishy!
Integers have the copy()
trait implemented
- Passing variables to functions will transfer ownership
- Returning variables in functions will also transfer ownership
- References allow you to take up the values without taking ownership. This is called borrowing
- References are immutable by default
- Borrowing a mutable reference more than once is not allowed
- Prevents compile-time data races
- You cannot borrow a mutable reference of a variable when an immutable reference is already borrowed