cargo new hello_world
cargo build
cargo build - -release
cargo check
cargo run
cargo doc - - open
cargo clippy (to get warnings about potentially useless code like return and semicolon)
- Rust
- Better TOML
- Rust (rls)
- rustfmt
Difference between an immutable variable and a const in rust is that a const can't be assigned a value that will be computed on run time and its convention is that the name is in ALL CAPS
const MAX_POINTS: u32 = 100_000;
2 types: scalar & compound
SCALAR:
-
integers (underscores are ignore in integers like 1_000_0 is same as 10000)
can initialize multiple variables likes so
Writing different types of integers
-
floating-point numbers
valid
ALSO valid: (can suffix type at the end as well with or without underscore, which again are ignored):
can also put underscore with numbers and types
-
Booleans
-
characters
COMPOUND:
-
The Tuple Type (Currently have arity[i.e. total members in tuple] of 12 after which although you can have more arity but not with full functionality) The tuple size can't grow or shrink it stays the same (arity of 3)
Destructuring:
-
The Array Type
(ARRAYS HAVE MAX LENGTH OF ***32*** IN RUST AFTER WHICH THEY LOSE THEIR MOST FUNCTIONALITIES )
Arrays in Rust are different from arrays in some other languages because arrays in Rust have a fixed length, like tuples.
Arrays are useful when you want your data allocated on the stack rather than the heap (we will discuss the stack and the heap more in Chapter 4)
use array only when you know the number of elements in it won't change etc. (like names of months) else use vector Vec
to initialize an array of same type a specific number of times (so the value 3, 5 times):
let a = [3; 5];
equal to :
CONST:
SCREAMING SNAKE CASE
TYPE ANNOTATION IS MANDATORY
VALUE SHOULD BE A LITERAL
There are total 6 types of strings in std lib but mostly we use 2:
-
string slice
str
will almost always see it as borrowed string slice&str
-
Second is
String
Capacity
may or may not be fully used a&str
is a subset ofString
Strings can't be indexed by character position so my_string[2] is invalid
-
THINGS YOU CAN DO IF YOU KINDA WANT TO INDEX THROUGH STRING
word.chars()
gives you an iterator to iterate through unicode scalarsor a library
-
Different methods to manipulate strings
you can also use .nth(index) along with an iterator to be able to go to an index
-
Difference is that in &str
data CANNOT be modified and in String
it CAN be!
need to call a .to_string()
on borrowed string slice to to convert it to String
OR
THIS is shadowing, meaning in a scope you can shadow a variable, it won't change its value but rather make a copy of it which will "shadow" its original value
value of the first x isn't accessible from the inner block after it is shadowed.
variables can be shadowed for different accessibility like:
and can also be shadowed to entirely different data type to drop intermediary usage/meaning of a variable in a code like:
Expressions never end with ;
RUST implicitly returns last expression as return value like:
but see here 5 in five() is an expression which is fine but if we added a ; at the end of it, it would become a statement hence won't be able to return any value
but if we add a return before 5; then it will be fine and will compile.
SOME POINTS ABOUT IF:
1. everything between `if` and `{` is a condition
2. Condition must evaluate to condition (RUST hate type coercion)
3. IF is an `expression` which means it returns value
SOME POINTS TO REMEMBER EVEN MORE!!
1. There are no ; after the branch values so values can be returned as tail value
2. we can't use `return` even if we wanted to, because return is for function values
3. all the arms (blocks from if and else) return the same type
4. `;` At the end of the entire IF expression; (IT IS MANDATORY TO PUT IT IF YOU USE THE VALUE, else you can drop it) - but make it a practice to always put ; after if
5: `{}` are mandatory
if:
you can't just say "if number{}" in rust like you can in JS
DON'T use too many if/else instead use match in rust
instead of ternary use:
let number = if condition { 5 } else { 88 };
this won't work, cause of mismatched types:
let number = if condition { 5 } else { "six" };
look at the break statement you can return what you want to after the break statement in a code
While loop for iterating over array:
there are different types of iters that can work in different ways to return calues
start inclusive, end exclusive:
both ends inclusive
you can label a loop in rust for example to break out of the top most loop instead of using other methods to achieve the same purpose;
like so:
'bob
similar stuff for continue:
Not valid: (scope for s ended on line 4)
Valid:
ownership has been moved from s1 to s2, and now s2 is uninitialized
line 1:
NOT POSSIBLE IN RUST FOR MEMORY SAFETY:
INSTEAD
on line 2 s2 exists on stack but is uninitialized now
Since s1 is immutable we can't reassign it to another value and we can't use it anymore. BUT you can still shadow it (but remember rules of shadowing told below)
like this works:
To make a copy of it, instead of moving just use `s1.clone()`
clone does the following under the hood (copy stuff in stack and heap)
RUST reserves the word COPY for only when stack
data is being copied.
For both stack
and heap
data CLONE is used
here the s1 got moved to the do_stuff() function and we can't use it
an approach could be that we make s1 a mut variable and the at the end of the do stuff function return s while moving the call like so s1 = do_stuff()
but come on that's ehh pattern. so that's why we'd now learn about REFERENCES AND BORROWING
Similarly: ERROR!!!!
references can't be used to change data of the referenced variables as references are defaulted to immutable BUT you can do that if you use mutable references like so:
NO ERROR!
using &
to pass references
under the hood:
in rust you almost never have to care about pointers cause it automatically handles creation and destruction of it and make sure they are always valid (using lifetimes) andddd you can never point to null
Compiler won't let you create a reference that outlive the data it is ultimately references
References defaults to immutable EVEN IF the value they refer to are immutable
for calling methods:
usually when trying to get a value from a reference we need to de reference it to "get" the actual value, but in rust you can use the .
operator (it auto deferences dowwnnnn (incase it is a ref of ref of ref ...) to the actual value):
for most other operators (like assignment operator ) you have to manually derefernce it like so:
dereferncing to get actual value
**YOU CAN HAVE Either (for one variable)
1. Exactly one mutable reference
2. Any number of immutable references**
it is to make sure that different mutable references can't change the value of a variable, and cause memory problems, in usual cases this will require some sort of locking but rust saves us from those stuff
Rust guarantees memory safety at compile time
not sure what to write the video explains it flawlessly
#[derive(Debug)] // !This enables using the debugging format string "{:?}"
- macros usually go with ! mark at end
- LET makes immutable variables here
- ALL the variables are by default immutable in rust
- to make it mutable
let mut b: i8 = 0
"mut" keyword
- to make it mutable
usize
&isize
are native variables meaning they'll use space of that processor, like 64 unsigned/signed integer respectivelyrm -rf ~/.cargo/.package-cache
rm -rf ~/.cargo/registry/index/*
Formatting Traits:
error: unknown format trait `s`
--> hello.rs:10:22
|
10 | println!("{} of {:s} people know binary, the other half doesn't", 1, 2);
| ^
|
= note: the only appropriate formatting traits are:
- ``, which uses the `Display` trait
- `?`, which uses the `Debug` trait
- `e`, which uses the `LowerExp` trait
- `E`, which uses the `UpperExp` trait
- `o`, which uses the `Octal` trait
- `p`, which uses the `Pointer` trait
- `b`, which uses the `Binary` trait
- `x`, which uses the `LowerHex` trait
- `X`, which uses the `UpperHex` trait
Implementing Display for custom structures
#[derive(Debug)]
struct Complex {
real: f64,
imag: f64
}
impl fmt::Display for Complex {
fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} + {}i", self.real, self.imag)
}
}