255 lines
7.4 KiB
Markdown
255 lines
7.4 KiB
Markdown
up:: [[Rust]]
|
|
tags::
|
|
|
|
## Rust Notes
|
|
|
|
### Rust is a modern systems programming language with:
|
|
- memory safety (no garbage collection)
|
|
- no null values
|
|
- no exceptions
|
|
- modern package manager and build system (similar to npm)
|
|
- no data races (race conditions)
|
|
|
|
---
|
|
|
|
### Installing rust
|
|
|
|
#### on macos/linux
|
|
after running command follow onscreen instructions
|
|
```Bash
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
```
|
|
|
|
to confirm installation success run the following:
|
|
```Bash
|
|
-> rustc --version
|
|
rustc 1.67.1 (d5a82bbd2 2023-02-07)
|
|
|
|
-> cargo --version
|
|
cargo 1.67.1 (8ecd4f20a 2023-01-10)
|
|
|
|
-> rustup --version
|
|
rustup 1.25.2 (17db695f1 2023-02-01)
|
|
```
|
|
|
|
#### in VSCode
|
|
install rust-analyzer extension
|
|
|
|
---
|
|
|
|
### Exploring Cargo
|
|
By running `cargo new <name>` you will create a new rust project containing a git repository
|
|
Calling `cargo new --help` will bring up help view
|
|
|
|
the `Cargo.toml` file is always at the root of a rust project. Its essentially the `package.json` in npm
|
|
The dependency section contains whats called `Crates`. The central registry for all crates is found at [Crates.io](crates.io).
|
|
|
|
after a crate is installed, youll see the name of the crate, the version, and a thumb meaning its isntalled
|
|
```toml
|
|
[dependencies]
|
|
package = 1.0.0 👍
|
|
```
|
|
|
|
#### Building project
|
|
To build the cargo project you run `cargo build`. This will build all crates and your rust code.
|
|
|
|
#### Running project
|
|
To run the cargo project you run `cargo run` which will execute the binary file that was previously built
|
|
|
|
#### System wide crates
|
|
We can also use cargo to install rust binaries that can be used system wide. A tool called `cargo-expand` can be installed by running `cargo install cargo-expand` in the terminal
|
|
> this takes a minute
|
|
|
|
cargo-expand is using the nightly build of cargo/rust so you cannot call it in the terminal yet
|
|
|
|
lets check what we have installed by running `rustup toolchain list`. Looks like we're on the stable version
|
|
|
|
lets install the nightly toolchain using the following command
|
|
```bash
|
|
rustup toolchain install nightly-aarch64-apple-darwin
|
|
```
|
|
|
|
Now if we run `rustup toolchain list`, we'll see the nightly and the stable with stable being default - we can now call `cargo expand` in the terminal
|
|
|
|
---
|
|
|
|
### The stack
|
|
Rust calculates the size of a stack frame at compile time
|
|
This means, if a function contains a variable, the stack frame will have just enough space for that variable. If a new frame is added with a parameter and a variable, the stack frame will have just enough space for the two variable, slightly larger than the previous stack frame
|
|
|
|
The stack has a limited size, determined by the machine architecture, and will result in a stack overflow error if you overflow the stack with something like infinite recursion
|
|
|
|
---
|
|
|
|
### The Heap
|
|
##### What is the heap?
|
|
- its a region fo the process emmory that is NOT auto managed
|
|
- it has no size restrictions
|
|
- its accessible by any function, anywhere in the program
|
|
- we should avoid heap allocations as they are expensive
|
|
|
|
When you allocate a value on the heap, you store a pointer to the address of the allocated data
|
|
```rust
|
|
POINTER e = ALLOCATE INTEGER 7
|
|
// e = 0xf578bb60
|
|
```
|
|
|
|
memory is manually allocated and deallocate on the heap. If you dont deallocate the memory, you will have a memory leak, which wont be released until the program exits
|
|
|
|
---
|
|
|
|
### Smart Pointers
|
|
smart pointers essnetially just deallocate the heap memory automatically
|
|
```rust
|
|
let e = Box::new(7);
|
|
```
|
|
|
|
---
|
|
|
|
### Memory layout of binary
|
|
> who cares
|
|
|
|
---
|
|
|
|
### Basic data types
|
|
u8 - unsigned 8 bit (can only be positive)
|
|
i8 - signed 8 bit (can be negative)
|
|
u/i + size (8,16,32,128)
|
|
|
|
bool - 0/1
|
|
usize, isize - positive/negative size
|
|
|
|
char - single character (always 4 bytes)
|
|
|
|
---
|
|
|
|
### Functions
|
|
the `main()` function is the entry point to any rust application
|
|
function names are written in snake case i.e. `some_function_name()`
|
|
annotate all parameters
|
|
annotate return type
|
|
```rust
|
|
fn some_func(arg: f32) -> f32 {
|
|
// return f32 type
|
|
// if you dont use return keyword and without semicolon, value will be implicitly returned
|
|
}
|
|
```
|
|
|
|
We may see functions with a BANG attached to it, like so `someFunc!()`. That BANG indicates that this function is a MACRO.. A macro essentially is a shortcut to template code. So when we call the macro function, it will expand the code on build to something like so:
|
|
```rust
|
|
someFunc!('some arg');
|
|
// expands to
|
|
bunc::of::junk -> stuff -> no idea what im writing{
|
|
match(junk){
|
|
no idea -> 'some arg'
|
|
}
|
|
}
|
|
|
|
// this is just an example, this is nothing like the actual syntax of rust
|
|
```
|
|
|
|
---
|
|
### Variables
|
|
we use the `let` keyword to define variables
|
|
```rust
|
|
let newVar = 5;
|
|
```
|
|
|
|
There's no need to define variable types as the rust compiler can usually infer the type
|
|
|
|
All variables in rust are immutable by default. If we try to update the variable, the compiler will cry about it.
|
|
```rust
|
|
let a = 'b';
|
|
a = 'c' // compiler error: variable immutable
|
|
|
|
let mut a = 'b';
|
|
a = 'c';
|
|
// a == 'c'
|
|
```
|
|
|
|
---
|
|
|
|
### Standard Library
|
|
[STD](doc.rust-lang.org/std)
|
|
Module I/O (std::io)
|
|
```rust
|
|
// need to allocate empty mutable string first
|
|
let mut value = String::new(); // value lives on heap since size is not known at compile time - String is type of smart pointer
|
|
io::stdin().read_line(&mut value);
|
|
```
|
|
|
|
---
|
|
|
|
### Ownership
|
|
there are a few rules that variables follow:
|
|
1. each value in rust is owned by a variable
|
|
2. when the owner goes out of scope, the value will be deallocated
|
|
`let mut input = String::new()` where input is owner of String
|
|
3. there can only be ONE owner at a time
|
|
(`let mut input = String::new()` where input is owner of heap allocated String)
|
|
|
|
when passing owner to function, the function parameter now becomes the owner, and when that function is finished executing, you can no longer use the initial variable
|
|
```rust
|
|
let mut input = String::new(); // input is now owner
|
|
some_fn(input); // some_fn parameter is now owner
|
|
io::stdin().read_line(&mut input); // throws error as input is no longer available
|
|
```
|
|
|
|
> if you dont like this, see Borrowing
|
|
|
|
---
|
|
|
|
### Borrowing
|
|
by passing references, we can "borrow" a variable
|
|
```rust
|
|
fn some_fn(s: &string){} // s is not the owner of the string due to &
|
|
|
|
let val = String::new();
|
|
some_fn(&val) // reference is immutable
|
|
|
|
let mut val = String::new()
|
|
some_fn(&mut val) // reference is mutable
|
|
```
|
|
|
|
WITHIN a scope, you can have only one of:
|
|
1. as many immutable references as you want
|
|
2. one mutable reference
|
|
```rust
|
|
// cannot borrow 'input' as immutable because its already borrowed as mutable
|
|
```
|
|
|
|
---
|
|
|
|
### Result Type
|
|
When a method returns a type `Result`, it returns essentially a javascript promise with a success (then) and an error (catch).
|
|
|
|
you can call `.unwrap()` on the result
|
|
if result was a success, the unwrap will yield the contents of the success
|
|
if result was an error, it will terminate the application
|
|
|
|
---
|
|
|
|
### Parse string to number
|
|
Sometimes when getting input from the user for a number, you want to actually do some operation on that number.
|
|
```rust
|
|
io::stdin().read_line(&mut value).unwrap()
|
|
```
|
|
say we want to convert this `value` to an `f32` - you would first need to ensure the string is trimmed
|
|
```rust
|
|
let new_value = value.trim();
|
|
```
|
|
then you can call parse on the string
|
|
```rust
|
|
new_value.parse::<f32>().unwrap();
|
|
```
|
|
the `<f32>` part is so `parse` an ensure what type we're wanting to convert it into
|
|
|
|
---
|
|
|
|
### Resources
|
|
For more details on rust syntax, go to this file [[Rust Syntax overview]]
|
|
|
|
---
|
|
|
|
### End
|
|
Now lets head on over to creating a http server [[Rust http server]] |