Skip to content

caleb-shelton/rust-book

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust book

My notes and code for working through the Rust book 🦀

Chapter 1

  • fn main() is where execution starts in all Rust programs
  • ! means using a macro
  • Cargo is Rust's build system and package manager
  • cargo new cargo build cargo run cargo check cargo build --release

Chapter 2

  • use for std and rand lib (an external crate)
  • let
  • match
  • loop
  • read_line expect trim parse
  • expect returns value in brackets if Result is an Err value, if Result is an Ok value, it will return the value Ok is holding

Chapter 3

Variables and mutability

  • const and type must be annotated!
  • "Shadowing" or reusing immutable variables by defining let on the same variable name after it is defined, the second variable overshadows the first until it itself is overshadowed or the scope ends. Shadowing also lets use reuse the variable name but change the type and retain immutability after the transformation.

Data Types

  • Integers i32 u32, etc
  • Floating points f64 f32
  • Numeric operations, remainder %
  • Boolean type true false
  • Character type char defined using single quotes let r = '🦀'
  • Compound types: tuples and arrays can group multiple values into one type
  • Use pattern matching on a tuple to destructure it (get all the individual values into their own variables)
  • Access the first element of a tuple, x, by using x.0
  • The tuple without any values () has a special name, "unit". Expressions implicitly return the unit value if they don't return any other value
  • Array elements must be of the same type
  • Arrays in Rust have a fixed length
  • Arrays are useful when you want your data allocated on the stack rather than the heap, or when you want to ensure you will always have a fixed number of elements
  • A vector, is a similar type to an array provided by the standard library, but can grow and shrink
  • You write an array’s type using square brackets with the type of each element, a semicolon, and then the number of elements in the array, like so: let a: [i32; 5] = [1, 2, 3, 4, 5];
  • Shorthand trick let a = [3; 5]; defines [3, 3, 3, 3, 3]
  • Access elements in an array using indexing a[0]
  • If you use user input for specifying which element to pick and choose an out of bound ones Rust will panick with a run time error, rather than let you continue like in some other low-level languages that will let you access invalid memory. If you try to access out of bounds index without ambigious user input, Rust will catch this and fail during the compilation stage.

Functions

  • main function, entry point of many programs
  • fn keyword
  • snake case for function and variable names is the conventional style
  • You must declare the type of every parameter in function definition
  • Function bodies contain a series of statements optionally ending in an expression. Rust is an expression based language. A statement is for example let y = 6;. An expression is 3 * 2 or even just 6 in the statement let y = 6;. Expressions don't include ending semicolons (the semicolon in the previous example is a semicolon for the statement not for the 6 expression).
  • Function returns -> must specify type. You can return implicitly with the final expression in the block of the body of a function
  • return keyword with a value

Control flow

  • if statement, needs a bool, will not try and convert non bool to bool, like JavaScript does, for example.
  • else else if
  • match is recommended over lots of else ifs
  • returning a value after a break
  • break and continue apply by default to the innermost loop, however you can use loop labels so it can apply to the labelled loop. Loop labels are defined with a single quote and name, like so: 'counting_up: loop {}
  • while
  • for
  • Range (1..4)
  • rev() to reverse the range

Chapter 4

Ownership

  • Ownership is a set of rules that govern how a Rust program manages memory. If any of the rules are violated, the program won't compile.
  • Main purpose of ownership is to manage heap data (as opposed to stack data)
  • Ownership rules: Each value in Rust has an owner, there can only be one owner at a time, when the owner goes out of scope the value will be dropped
  • String datatype lives on the heap, and so good example for explaining ownership in Rust. Also note, String is different to string literals. There are two different types of string in Rust.
  • We can't allocate a dynamic piece of memory into the binary we compile, so it must allocated on the heap at runtime. We need a way of returning this mmeory to the allocator when we're done with our String.
  • Rust takes a different approach to garbage collectors and letting programmers free and allocate, which is error-prone. The memory is automatically returned once the variable that owns it goes out of scope.
  • Rust calls drop (a special function) behind the scenes
  • Deep copies vs shallow copies. Because Rust also invalidates the first variable it is called a move instead of shallow copy.
  • clone() arbitrary code (however it is implemented) is being executed and it could be expensive
  • Types stored on stack, we can implement the Copy trait. This means variables won't move, but are copied. Making them valid after assignment to another variable (unlike heap allocated types)
  • When sending a variable (which could be heap or stack based) to a function, just like assinging to variables move or copy is called. So once you pass a variable to a function and it gets moved then you cannot reference that variable after the call to the function.

References and borrowing

  • Rather than returning a tuple with the value you pass in so it is not droped we can use a reference &

About

Notes and code while working through Rust's official book

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages