Rust Notes
Last Updated:
Some notes I took on Rust when I was trying to learn it last year
Notes
rustc
to compile program to executable!
to specific a function is a macrocargo check
to check with code compiles without building an executablecargo build --release
builds code for production::
denotes associated function, called by the type (like string) (similar to Java static method)Result
is an enum type for error handling. can either beOk
orErr
. use in combination with.expect("error message")
to display a message on error or just return the value on success.Cargo.lock
keeps versions of crates the same as first build,cargo update
updates cratescargo doc --open
to generate documentation for your project and its crates (awesome)Ordering
is another enum withLess
,Greater
,Equal
for comparisoni32
(32 bit integer) is default type for numbers. signed integers are +/-, unsigned integers + onlytrim()
to remove whitespace from a stringparse()
to convert a string to a numberloop
for infinite looplet
can not be used in global scope,const
can.const
must be type annotated and is always immutable- a variable is shadowed when it is declared in a new scope. a new variable is created, original is noted mutated.
- tuples are fixed length and can hold multiple data types, access elements with
.index
- arrays are fixed length and can only only one data type, access elements with
[index]
- vectors can grow and shrink in size
- statements do not return values (ex:
let num = 5;
) - statements always end in semi-colons
- expressions return values that can be saved to variables (ex:
4 + 4
, functions) - expressions do not end in semi-colons, adding a semi-colon turns it into a statement.
- non-booleans are not converted to booleans in conditional expressions like in javascript
if
is an expression can be used likelet num = if condition { 5 } else { 6 }
- can
break
parent loops using loop name - loops are expressions and can be saved to variables
- stack = data is of known and fixed size
- heap = allocate data to pointer, pointer can be stored on stack
- ownership rules
- each values has one owner
- when the owner goes out of scope, the value is dropped
{
let s = "hello";
// s is valid
}
// function `drop` is automatically called
// s is no longer valid, it is dropped due to ownership rules
- string literals are immutable,
String
is mutable.let s = String::from("helo");
to create aString
from string literal
::
calls function from namespace- heap data is not copied when creating a new variable another variable, that new variable becomes a pointer
fn main() {
let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1);
// fails to compile, s1 is no longer valid.
// this is to prevent double free error
// called a move insead of a shallow copy
}
.clone()
for deep copies of data stored on heap- types with
Copy
trait are copied rather than moved - all scalar types and tuples containing only scalars implementCopy
- passing a value to a function or returning it transfers ownership
- can return multiple values from a function with a tuple
- pass by references with
&
to avoid transferring ownership &mut
to define a mutable references- if you have a mutable reference to a value, you can’t have any other references to that variable. this is to prevent data races
- cant combine mutable and immutable references, no mutable borrowing
let slice = &s[..]
creates a slice ofs
from index 0 to 2.- string literals are slices,
&str
, immutable references struct
fields are either all mutable or all immutablestruct
and struct update syntax similar to javascript objects and object destruct syntax- struct update moves data
- tuple structs are basically named tuples, ex:
struct Color(i32, i32, i32)
orstruct Coordinate(i32, i32)
#[derive(Debug)
over structs to add debug format when printingdbg!
takes ownership,println!
does notimpl
for creating associated methods for structs- automatic referencing and dereferencing when calling methods
- use
Struct_Name::function()
to call an associated function - methods can only be called on instance of a struct, functions are not
- can define enums with associated values like so
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
- can define methods on enums with
impl
same as you can with structs - Rust does not have
null
types, useOption<T>
enum
enum Option<T> {
None,
Some(T),
}
match
andenum
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
match
andOption
fn main() {
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
}
match
arms must cover all possibilitiesother
to cover all other possible values inmatch
, use__
when you don’t want to use the valueif let
for shorthand match
let mut count = 0;
match coin { Coin::Quarter(state) => println!("State quarter from {:?}!", state),
_ => count += 1, }
and
let mut count = 0;
if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}!", state);
} else {
count += 1;
}
are equivalent.
- binary crates are executable code with a
main
function; library crates have nomain
functions - crate root is the root module of your crate
- a package is a bundle of 1+ crates, contains at most one library crate
- Cargo automatically looks for src/main.rs or src/lib.rs
- multiple binary crates can be place in src/bin