语法
# 变量
// 不可变变量
let foo = 1;
// 可变变量:mut关键字为可变变量,没有则为不可变变量
let mut guess = String::new(); // :: 相当于调用静态方法
// 隐藏
foo = 2; // 会报错
let foo = 2; // 不报错,相当于重新声明一个foo变量,并将之前的隐藏
let foo = "Two"; // 新声明的变量可以是其他类型。
// 指定类型,如不指定类型则使用类型推断,rust可在编译时根据下文推到。
let x: u32 = 1;
# 常量
const MAX_POINTS = 100_0000;
- 可声明在任何作用域
- 名字命名规范全大写,下划线分割单词
- 数值可使用下划线分割增加可读性
# 数据类型 - 标量类型
Note
存储在 Stack
# 整数
类型长度
Length | Signed | Unsigned |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | isize | usize |
isize
、usize
的位数由程序运行的计算机的架构所决定,如 64 位计算机则为 64 位- 默认类型为
i32
定义(字面值)
Number Literals | Example |
---|---|
Decimal | 98_222 |
Hex | 0xff |
Octal | 0o77 |
Binary | 0b1111_0000 |
Byte(u8 only) | b'A' |
- 除了 Byte 类型(只能是 u8)以外,其他数值字面值可使用类型后缀,如
57u8
# 浮点数
- f32,32 位,单精度
- f64,64,双精度,默认类型
# 数值运算
let sum = 5 + 10;
let difference = 95.5 - 4.3;
let product = 4 * 30;
let guotient = 56.7 / 32.2;
let reminder = 54 % 5;
# 布尔
let t = true;
let f: bool = false;
# 字符
let x = 'z';
let y: char = "N";
# 数据类型 - 复合类型
# 元组 - Tuple
let tup: (i32, f64, u8) = (500, 6.4 ,1);
// 读取值:解构(与ES的解构赋值类似)
let (x, y, z) = tup;
println!("{}, {}, {}", x, y, z);
// 读取值:索引读取
println!("{}, {}, {}", tup.0, tup.1, tup.2);
- 长度固定,一旦声明就无法改变
- 元素类型不必相等
# 数组
let months = [
"January",
"……",
"Decmber",
];
// 定义i32类型长度5的数组
let a: [i32;5] = [1,2,3,4,5];
// 另一种初始化方式:指定数组初始化值
let b = [3; 5];
// 相当于
let b = [3,3,3,3,3];
// 读取
let first = months[0];
- 数组声明后,长度不可变
# 动态数组 - Vector
# 函数
# 结构
fn fn_name(x: i32, y: i64) { // 入参必须定义参数类型
println!("the value og x is : {}", x);
}
# 表达式
fn fn2() {
let x = 5;
let y = {
let x = 1;
x + 3 // 注意这里是没有;的,有就返回`()`了
};
println!("y={}", y); // y=4
}
# 返回值
- 在
->
符合后面声明函数返回值的类型,但是不可以为返回值命名 - 函数体最后一个表达式的值为返回值。大多数函数都是默认使用最后一个表达式为返回值
- 若要提前返回,需要使用
return
关键字,并指定一个值;
fn five() -> i32 {
5 // 返回5,主要这里没有;
}
# 注释
与 Java 类似
//
/* */
# 控制流
# if
let number = 3;
if number < 5 { // 必须是布尔类型,有别于js
....
} else if number > 100 {
} else {
....
}
因为 if
是一个表达式,所以可以将它放在 let 语句中等号的右边:
fn fn3() {
let condition = true;
let number = if condition { 5 } else { 6 }; // 类似于三元表达式
println!("The value of number is: {}", number);
}
# loop
死循环,直到遇到 break
loop {
……
}
fn fn4() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {}", result);
}
# while
let mut numer = 3;
while numer != 0 {
println!("{}", numer);
numer = numer - 1;
}
println!("LIFTOFF!!!")
# for
# 遍历数组
let a = [1, 2, 3, 4, 5];
for element in a {
println!("{}", element);
}
# 数值遍历
for number in (1..4) {
// 遍历从1-3的值,不包括4
}
for number in (1..4).rev {
// 遍历从3-1的值,不包括4
}
# 所有权
# Stack 和 Heap
- Stack,栈,后进先出(LIFO)
- 存储在 Stack 上的数据必须拥有已知的固定大小,反之则必须存储在 heap 上
- heap 性能较差些,但会分配较大空间,而此空间对应的指针是已知固定的,可存放在 stack 上。(有点 JVM 的味道) 数据访问
- stack 可直接读取,而 heap 的数据需要先在 stack 找到指针才能找到对应的 heap,因此会慢一些
# 移动
有别于浅拷贝,Rust 采用一种名为移动(Move)的方式,如下文,s1 赋值到 s2 后,s1 就失效了。
let s1 = String::from("Hello");
let s2 = s1;
println!("{}", s1); // 这里会报错,s1已经移动到s2
# 克隆
即深拷贝
let s1 = String::from("Hello");
let s2 = s1.clone();
println!("{}, {}", s1, s2); // 正常输出
除了上述这种 Stack、Heap 都发生复制的情况,还有只复制 Stack 的。(由于标量类型只存在与 Stack)
let x = 1;
let y = x;
上次更新: 2025/04/17, 14:57:47
← 入门 常见库(Crate)→