Rust Learning#
Basics#
-
Variables#
let a = 10; // a is immutable let mut a = 10 // a is mutable
Rust automatically releases memory when a variable goes out of scope, and Rust automatically calls drop at the closing }
-
Basic Types#
2.1 Numeric Types#
Statement: A specific operation with no return value
Expression: An expression always returns a value
fn add_with_extra(x: i32, y: i32) -> i32 { let x = x + 1; // statement let y = y + 5; // statement x + y // expression }
2.2 Character, Boolean, and Unit Types#
String type: Dynamic string type, allocated on the heap
let mut s = String::from("hello"); s.push_str(", world!") // appending a literal to the string
Characters in Rust are of Unicode type, so each character occupies 4 bytes
Strings are UTF-8 encoded, and the number of bytes occupied by characters in a string varies (1-4)
-
Append
let mut s = String::from("Hello ") s.push_str("rust") s.push('!')
push(): Appends a character
push_str(): Appends a string
Both methods append to the original string and do not return a new string, so the string must be mutable, marked with the mut keyword
-
Insert
let mut s = String::from("Hello rust!") s.insert(5, ',') s.insert_str(6, " I like")
String insertion operations modify the original string, so the string must be mutable, marked with the mut keyword
-
Replace
replace
let string_replace = String::from("I like rust") let new_string = string_replace.replace("rust", "Rust")
replacen
let s_replace = "I like rust learn rust" let ns_replacen = s_replace.replacen("rust", "Rust", 1)
String replacement operations return a new string rather than modifying the original string
replace_range: Only uses String type
let mut s_replace_range = String::from("I like rust") s_replace_range.replace_range(7..8, "R")
This method directly modifies the original string and does not return a new string, so it must be marked with the mut keyword
-
Delete
pop: Deletes and returns the last character
let mut s_pop = String::from("rust pop 中文!") let p1 = s_pop.pop()
This method directly modifies the original string but has a return value; if the string is empty, it returns None
remove: Deletes and returns the character at a specified position in the string
let mut s_remove = String::from("rust remove 中文") string_remove.remove(0)
This method directly modifies the original string but has a return value
truncate: Deletes all characters from a specified position to the end of the string
let mut s_truncate = String::from("测试truncate") s_truncate.truncate(3)
This method modifies the original string and has no return value
clear: Clears the string
let mut s_clear = String::from("string clear") s_clear.clear()
This method directly modifies the original string, equivalent to s_clear.truncate(0)
-
Concatenate
Use + or += to concatenate strings, requiring the right-hand parameter to be a slice reference type
- returns a new string, so the variable declaration does not need to be marked with the mut keyword
2.3 Tuples#
let x : (i32, f64, u8) = (500, 6.4, 1); let a = x.0; let b = x.1;
2.4 Structs#
- Initialize instances, each field must be initialized
- The order of initializing fields does not need to match the definition
- When function parameters and struct fields have the same name, shorthand initialization can be used
- user2 differs from user1 only in email, so only the email needs to be assigned, the rest can be done with ..user1
fn build_user(email: String, username: String) -> User { User { email, username, active: true, sign_in_count: 1, } }
let user2 = User { email: String::from("[email protected]"), ..user1 };
Unit structs: Do not care about the content of this type, only care about its behavior
struct AlwaysEqual; let subject = AlwaysEqual; impl SomeTrait for AlwaysEqual {}
Struct output printing
- Manually implement Display, Debug
- Use derive
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } println!("rect1 is {:?}", rect1)
2.5 Ownership and Borrowing#
- Every value in Rust is owned by a variable, which is called the owner of the value
- A value can only be owned by one variable at a time, or in other words, a value can only have one owner
- When the owner (variable) goes out of scope, the value will be dropped, and Rust will automatically call the drop function to clean up the variable's heap memory
let s1 = String::from("hello"); let s2 = s1; println!("{}, world!", s1)
After s1 is assigned to s2, Rust considers s1 no longer valid, so there is no need to drop anything after s1 goes out of scope. This means ownership of s1 is transferred to s2, and s1 becomes invalid immediately after being assigned to s2. Rust prohibits the use of invalid references.
let x = 5; let y = x;
First, 5 is bound to variable x, then the value of x is copied to y, resulting in both x and y being equal to 5. Integers are Rust's basic data types, fixed-size simple values, so both values are assigned by automatic copying and are stored on the stack, with no need for heap memory allocation.
2.6 References and Borrowing#
Getting a reference to a variable is called borrowing
-
Immutable Reference
fn main() { let s1 = String::from("hello"); let len = calculate_len(&s1); println!("the len of '{}' is {}.", s1, len); } fn calculate_len(s: &String) -> usize { s.len() }
-
Mutable Reference
fn main() { let mut s = String::from("hello"); change(&mut s); } fn change(some_string: &mut String) { some_string.push_str(", world"); }
- Immutable references can exist simultaneously in multiple instances
- Mutable references can only exist one at a time
- Mutable and immutable references cannot coexist
-