1 Overview
Rust is a compiled language (AOT - ahead of time), which needs to be compiled before generating executable code, which is fundamentally different from interpreted languages such as JavaScript.
2. Variables and Mutability
In Rust, variables are declared by let, but variables declared by let are immutable (_Immutable_) variables by default.
If you try to modify the value of a variable after the let declaration, an error will be reported at compile time.
fn main() {
let a = 5;
a = 6; // error: cannot assign twice to immutable variable
}
We can use the following two ways to solve this problem
When a variable is declared, let is modified with the mut keyword, indicating that it is a mutable variable. It should be noted that Rust is a strongly typed language, so even if declared as a mutable variable, it can only be reassigned to a value of the same data type
fn main() { let mut a = 5; a = 6; // 改变数据类型,编译报错 a = "6"; // error: expected integer, found `&str` }
Using the shadowing feature, declaring this variable again overrides the previous value and is not restricted by the previous data type. Equivalent to re-declaration, the previous variable is hidden
fn main() { let a = '5'; // '5' let a = 5; // 5 let a = a + 1; // 6 let a = a * 2; // 12 }
3. Constants
In Rust, constants are declared through the const keyword. The difference between constants and variables is
- The mut keyword cannot be used
- Constants must specify a data type when they are declared
- Constants can be declared at any scope, including the global scope
- Constants can only be bound to constant expressions
Naming convention: all letters are capitalized, and words are connected by _, such as
const MAX_AGE: u32 = 10_0000;
4. Data Types
4.1 Scalar Types
4.1.1 Integer Types
- Signed integers start with i $$[-(2^n-1) , 2^{n-1}-1]$$
- Unsigned integers start with u $$[0 , 2^n - 1]$$
- The number of bits of isize and usize types is determined by the architecture of the computer the program runs on. On a 64-bit computer, it is 64-bit.
- The default type for integers is i32
4.1.1.1 Integer literals
- Start with 0x in hexadecimal
- Octal starts with 0o
- Start with 0b in binary
- The data type of the byte type is limited to u8, starting with b
Except for the byte type, all numeric literals allow type suffixes, such as
// 表示 u8 类型的数值 57
let a = 57u8;
4.1.1.2 Integer overflow
If you set a variable of type u8 (0-255) to 256, the following will happen:
- In development mode, Rust detects an overflow and panics when the program runs
In release mode, Rust doesn't detect overflow, and wraps around when it happens:
- 256 -> 0
- 257 -> 1
- ...
4.1.2 Floating point types
- f32, single precision
- f64, double (the default type for Rust floats, since f64 is about as fast as f32 on modern CPUs)
- Rust floating point types use the IEEE-754 standard
4.1.3 Boolean Type
- occupies one byte
- symbol is bool, value is true | false
4.1.4 Character Type
- The symbol is char
- Use single quotes for literal values
4.2 Composite Types
4.2.1 Tuples
- Immutable length after declaration
Values of different data types can be grouped together
// 声明一个元组 let tup: (i32, f64, u8) = (500, 5.6, 23); // 获取元组成员 // 1.解构 let (x, y, z) = tup; println!("{}, {}, {}", x, y, z); // 500, 5.6, 23 // 2.点标记法 println!("{}, {}, {}", tup.0, tup.1, tup.2); // 500, 5.6, 23
4.2.2 Arrays
- Like tuple, the length is immutable after declaration
- The data types of the array members must be the same
- Arrays are stored in stack memory
The type of the array is represented by the form [type; length]
let arr: [i32; 5] = [1,2,3,4,5]; // 特殊的数组声明方法 let sameMemberArray = [3; 5]; // [3,3,3,3,3] // 访问数组成员 let f = arr[0]; // 1 // 访问数组越界 - rust编译器会进行简单的越界检查 let more = arr[6]; // 编译报错 // 访问数组越界 - rust编译器检测不到的场景 let temp = [6,7,8,9]; let more_temp = arr[temp[0]]; // 编译通过,运行时报错
5. Functions
- Declare a function with the fn keyword in Rust
- For function and variable names, use snake case conventions (words are lowercase, spliced with _)
- Parameters must specify a data type when they are defined
- If you want to return a value early, use the return keyword
The default return value of the function is an empty tuple
fn main() { let number = get_number(5); println!("{}", number); // 10 } fn get_number(a: i32) -> i32 { // 函数中最后行如果是表达式,那么表达式的值则会作为函数的返回值 // 如果行尾加了分号,则会被识别为语句,就不会被作为函数的返回值 a + 5 }
6. Control Flow
6.1 Conditional branch - if
It should be noted that if each branch block has a return value, the data type must be the same
let a = 3; // if else if a == 3 { println!("a is 3"); } else { println!("a is not 3"); } // 使用 表达式 的特性达到其他语言中 三元表达式 的效果 let b = if a == 3 { 5 } else { 6 }; // 5
6.2 Loops
loop
- loop will execute the code in the loop body in an infinite loop until interrupted by break
- break can provide a return value for the loop expression
// loop 循环 let mut count = 0; let value = loop { count += 1; if count == 10 { break count * 2; } } println!("{}", value); // 20
while
let arr = [1,2,3,4,5]; let mut index = 0; // 使用 while 循环遍历数组 while index < 5 { println!("{}", arr[index]); index = index + 1; }
for
let arr = [1,2,3,4,5]; for item in arr.iter() { println!("for item {}", item); } // 使用 range 实现指定次数的循环 // 1. (1..5) -> 一个包含 1,2,3,4 的可迭代器 // 2. 使用 rev 方法进行反转 for item in (1..5).rev() { println!("range item is {}", item) }
7. Ownership
Ownership is a core feature of Rust that ensures memory safety without GC
7.1 Memory and Allocation
When the variable goes out of scope, Rust will automatically call the drop function to return the memory space to the operating system
7.2 Data copy on Stack: copy
For simple scalar data types, the following code will eventually push two 5's onto the stack
- Essentially because scalar types implement the Copy trait
- Copy This trait is used for data types such as integers that are stored on the stack. Data types that need to allocate memory cannot implement this trait.
- If the Copy trait is implemented, the old variable can still be used after assignment
- If a type implements the Drop trait, Rust will not allow it to implement the Copy trait.
Data types with the Copy trait
- integer
- floating point number
- boolean
- character
- Ancestor (need to satisfy the data types that all members have Copy trait)
let x = 5; let y = x; println!("{}, {}", x, y); // 5, 5
7.3 The way variables interact with data: move
Corresponding to the composite data type of unknown length, after assigning one variable to another variable, the former will become invalid (called move in Rust, that is, the memory space pointed to by s1 is moved to s2, and after the move is completed, s1 will become invalid. , so as to avoid two release operations for the same memory space when s1 and s2 go out of scope)
- Double free is a serious bug in other languages that require manual memory control, and may free memory that is being used by other programs, causing unknown problems
let s1 = String::from("haha"); let s2 = s1; println!("{}", s1); // error: value borrowed here after move
7.4 Ownership and Functions
In fact, the situation of passing values to functions and variables is similar, move or copy will occur
fn main() { let string = String::from("hello"); // Move,所有权发生移动,传入到了函数作用域中 move_case(string); /* * 在调用 move_case 时,string指向的内存空间 的所有权发生了 move, * 当 move_case 调用完毕时,string指向的内存空间已经被释放了, * 所以之后再访问 string,编译时就会报错 */ // println!("{}", string); // value borrowed here after move // --------------------------------------------------------------------- let number = 12; // Copy,传入 number 值的副本 copy_case(number); /* * number 是简单的标量类型,实现了 Copy trait * 在调用 copy_case 时,仅仅是传入了一个副本, * 所以后续任然可以继续使用 */ println!("{}", number); // --------------------------------------------------------------------- let bar = String::from("bar"); /* * 在以下函数的调用过程中,bar 指向的内存空间的 所有权 被移动到了 函数作用域 中, * take_ownership_and_return 这个函数的作用是得到一个内存空间的所有权并将其返回, * 最终 foo 拿到了该内存空间的 所有权,其实这段代码的效果与 let foo = bar; 相同 */ let foo = take_ownership_and_return(bar); println!("{}", foo) } fn move_case(string: String) { println!("{}", string); } fn copy_case(number: u32) { println!("{}", number); } fn take_ownership_and_return(s: String) -> String { s }
8. Stack & Heap
- stack is a contiguous memory space
- The heap is the hashed memory space, and the pointer to the heap memory is stored in the stack
- All data stored on the stack must have a known size, data whose size is unknown at compile time or whose size may change at runtime must be stored on the heap
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。