6.8 KiB
title, description, draft, tags, author, showToc
| title | description | draft | tags | author | showToc |
|---|---|---|---|---|---|
| rust | true | TrudeEH | true |
Vocabulary
| Command / Word | Action / Meaning | Example |
|---|---|---|
| Statement | Performs an action, but does not return a value. | Function definitions, code that ends with ;. |
| Expression | Evaluate to a resultant value. | Tests, math. |
Tools
- Install Rust:
curl --proto '=https' --tlsv1.2 -sSf <https://sh.rustup.rs> | shrustuprustccargo
Hello World!
fn main() {
println!("Hello world!");
}
Variables
let x: i32; // A variable can only be used if it has been initialized (contains a value)
let y: i8 = 5; // All variables are constant by default.
let mut z = 1; // The mut keyword makes the variable mutable. (Explicit type annotation is not necessary, but recommended).
let (k, f); //Same as "let k; let f;"
let t = { // Initialize a variable as the result of an expression.
let squared = y * y;
squared
};
Data Types
Integer Types
| Length | Signed | Unsigned | Unsigned Decimal Length |
|---|---|---|---|
| 8-bit | i8 |
u8 |
0..=255 |
| 16-bit | i16 |
u16 |
0..=65535 |
| 32-bit (default) | i32 |
u32 |
0..=4294967295 |
| 64-bit | i64 |
u64 |
0..=18446744073709551615 |
| 128-bit | i128 |
u128 |
0..=340282366920938463463374607431768211455 |
| arch | |||
| (Size of CPU architecture) | isize |
usize |
The size of a memory address. |
let v: u16 = 32_u8 as u16; // Convert an u8 type to u16.
println!("{}", i8::MAX); // Print the largest possible value a data type can hold.
let a = 10_000; // _ is ignored, and is only used to help with readability.
let b = 1 + 0xff + 0o77 + 0b1111_1111; // Various numerical bases are supported.
println!("{}", type_of(&v));
Floating Point Values
| Length | Signed | Unsigned | Unsigned Decimal Length |
|---|---|---|---|
| 8-bit | f8 |
u8 |
0..=255 |
| 16-bit | f16 |
u16 |
0..=65535 |
| 32-bit (default) | f32 |
u32 |
0..=4294967295 |
| 64-bit | f64 |
u64 |
0..=18446744073709551615 |
| 128-bit | f128 |
u128 |
0..=340282366920938463463374607431768211455 |
assert!(0.1 + 0.2 == 0.3); // False, floating point numbers are subject to imprecision.
assert!(0.1_f32 + 0.2 as f32 == 0.3_f32); // True. f32 is less precise. (Note: Remember that _ are optional and are ignored.)
Boolean Logic
| True | False |
|---|---|
true |
false |
1 |
0 |
let _f: bool = false; // 1 byte
let t = false;
if !t { println!("t became true") }
Boolean Operators
ANDORNOT
Bitwise Operations
Each bit is considered a unit.
| AND | & |
|---|---|
| OR | ` |
| XOR | ^ |
| LEFT SHIFT | << |
| RIGHT SHIFT | >> |
Characters
let c1: char = 'a'; // 4 bytes
let c2: char = 'µ'; // Unicode is supported
Unit Type
let _v: () = (); // () is similar to null. It means nothing. Takes up 0 bytes.
Range
-3..2 // -3 to 1. 2 is excluded.
'a'..='z' // a to z. z is included.
Scope
A scope can be created anywhere in the program.
// Global Scope
let y = 2;
{
// Local Scope. x is not accessible outside this scope.
let x = 1;
println!("{} and {}", x, y);
}
If a variable inside the inner scope has the same name as one outside, the latter is shadowed.
Functions
fn main() { // No output; Implicit "-> ()".
sum(3, 2);
}
fn sum(x: i32, y: i32) -> i32 { // Takes 2 numbers as input, and outputs another.
x + y;
}
fn never_return() -> ! { // "-> !" A function that never returns to the caller. Either panics, or loops forever.
panic!() // Error.
unimplemented!() // Use if a function is not implemented yet.
todo!() // Incomplete.
}
Type annotation is required in function definitions.
Ownership
- 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.
{
let s = "example";
| |
Owner Value
}
// Outside this scope, s is dropped from memory.
Borrowing
- Access data without taking ownership of it.
- When borrowing, you are taking a reference (pointer) to the data, not the value itself.
Rules
- At any given time, you can have either one mutable reference or any number of immutable references.
- References must always be valid.
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len() // s is a pointer to s1
}
Example mutable reference:
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
Get the address in memory:
let x = 5;
let p: &i32 = &x; // Reference to x, reads 5 by println!.
println!("The memory address of x is {:p}", p); // :p reads the raw reference value.
Dereference:
let x = 5;
let p: &i32 = &x; // Reference to x
assert_eq!(5, *p) // Go to the value p points to and read it.
The ref keyword is an alternate syntax to create a reference:
let c = 'T';
let r1 = &c;
let ref r2 = c;
Compound Types
Data types made of other types.
Strings
A String is mutable, and is stored on the stack with a pointer to the heap, where the value is stored.
let s1 = String::from("hello");
| |
Pointer Array stored on the heap
(usize)
Copy vs. Move
// Copy a value
let x = 1;
let y = x;
// Move the pointer value.
let s1 = String::from("hello");
let s2 = s1;
Now s2 also points to the same string as s1. This is not allowed in rust, so s1 will be dropped. (Passing a string pointer to a function makes the function the new owner of the string).
// Copy a string (Deep Copy)
let s1 = String::from("hello");
let s2 = s1.clone();
In this example, the value in the heap is copied, so both s1 and s2 have their own values, and only own their own instance of the string.
String Vs. &str
| Type | Mutability | Ownership | Efficiency |
|---|---|---|---|
String |
Mutable; heap | Owns its contents | - |
&str (String Slice) |
Immutable; stack | Does not own data | + |
"..." (String Literal) |
Immutable; static storage (Stored inside the compiled program) | Does not own data | +; Same as &str |
let s1: String = String::from("hello");
let s2: &str = "Hello";
// Read String Slice
let read_string_slice = &s2[0..1]; // "he"
// Move str to heap to make it mutable.
let s: Box<str> = "hello, world".into(); // .into() converts to the variable type.
let str_again = &s;
Tuples
Store different data types.
let t: (String, Int) = (String::from("hello"), 14);
Reference: https://youtu.be/BpPEoZW5IiY?si=WiJX41VB55S7Tx17&t=5607