1. 赋值语句
let
fn main() {
let a: u32 = 1;
}
2.数字类型
整数
浮点数
浮点数有两种类型:f32和f64,分别代表32位浮点数类型和64位浮点数类型。它们也可以跟在字面量的后面,用来指定浮点数值的类型,比如 let a = 10.0f32; 就定义了一个变量a,初始化成32位浮点数类型,值为10.0。
3. 布尔类型
true 和 false。
let a = true; let
b: bool = false;
4.字符
Rust中的字符类型是 char,值用单引号括起来。
fn main() {
let c = 'z';
let z: char = 'ℤ';
let heart_eyed_cat = '?';
let t = '中';
}
Rust的 char 类型存的是Unicode 散列值,char类型在内存中总是占用 4 个字节大小
5.字符串
Rust中的字符串类型是 String,String内部存储的是Unicode字符串的UTF8编码
let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("你好");
字符串字面量中的转义
fn main() {
// 将""号进行转义
let byte_escape = "I'm saying \"Hello\"";
println!("{}", byte_escape);
// 分两行打印
let byte_escape = "I'm saying \n 你好";
println!("{}", byte_escape);
// Windows下的换行符
let byte_escape = "I'm saying \r\n 你好";
println!("{}", byte_escape);
// 打印出 \ 本身
let byte_escape = "I'm saying \\ Ok";
println!("{}", byte_escape);
// 强行在字符串后面加个0,与C语言的字符串一致。
let byte_escape = "I'm saying hello.\0";
println!("{}", byte_escape); }
6.数组
Rust中的数组是array类型,用于存储同一类型的多个值。数组表示成[T; N],由中括号括起来,中间用分号隔开,分号前面表示类型,分号后面表示数组长度。
fn main() {
let a: [i32; 5] = [1, 2, 3, 4, 5];
let a = [1, 2, 3, 4, 5];
}
7.动态数组
Rust中的动态数组类型是Vec(Vector),也就是向量,中文翻译成动态数组。它用来存储同一类型的多个值,容量可在程序运行的过程中动态地扩大或缩小,因此叫做动态数组。
fn main() {
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];
let mut v = Vec::new();
v.push(5); v.push(6);
v.push(7); v.push(8);
}
8.哈希表
哈希表是一种常见的结构,用于存储Key-Value映射关系,基本在各种语言中都有内置提供。Rust中的哈希表类型为HashMap。对一个HashMap结构来说,Key要求是同一种类型,比如是字符串就统一用字符串,是数字就统一用数字。Value也是一样,要求是同一种类型。Key和Value的类型不需要相同。
fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50);
}
复合类型
9.元组
元组是一个固定(元素)长度的列表,每个元素类型可以不一样。用小括号括起来,元素之间用逗号隔开。例如:
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 元组使用.运算符访问其元素,下标从0开始,注意语法
let five_hundred = x.0;
let six_point_four = x.1;
let one = x.2;
}
与数组的相同点是,它们都是固定元素个数的,在运行时不可伸缩。与数组的不同点是,元组的每个元素的类型可以不一样。元组在Rust中很有用,因为它可以用于函数的返回值,相当于把多个想返回的值捆绑在一起,一次性返回。
当没有任何元素的时候,元组退化成 (),就叫做unit类型,是Rust中一个非常重要的基础类型和值,unit类型唯一的值实例就是(),与其类型本身的表示相同。比如一个函数没有返回值的时候,它实际默认返回的是这个unit值。
10.结构体
Rust中使用 struct 关键字来定义结构体,每个字段的类型可以不一样
struct User {
active: bool,
username: String,
email: String,
age: u64,
}
fn main() {
let user1 = User {
active: true,
username: String::from("someusername123"),
email: String::from("someone@example.com"),
age: 1,
};
}
11.枚举
Rust中使用 enum 关键字定义枚举类型。比如:
enum IpAddrKind {
V4,
V6,
}
枚举类型里面的选项叫做此枚举的变体(variants)。
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
以看到,枚举类型也是一种复合类型。但是与结构体不同,结构体类型是里面的所有字段(所有类型)同时起作用,来产生一个具体的实例,而枚举类型是其中的一个变体起作用,来产生一个具体实例,这点区别可以细细品味。学术上,通常把枚举叫作和类型(sum type),把结构体叫作积类型(product type)。
控制流
12.分支语句
Rust中使用if else来构造分支。
fn main() {
let number = 6;
// 判断数字number能被4,3,2中的哪一个数字整除
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
let x = 1;
// 在这里,if else 返回了值
let y = if x == 0 {
// 代码块结尾最后一句不加分号,表示把值返回回去
100
} else {
// 代码块结尾最后一句不加分号,表示把值返回回去
101
};
println!("y is {}", y);
}
13. 循环语句
Rust中有三种循环语句,分别是loop、while、for。
- loop用于无条件(无限)循环。
fn main() {
let mut counter = 0;
// 这里,接收从循环体中返回的值,对result进行初始化
let result = loop {
counter += 1;
if counter == 10 {
// 使用break跳出循环,同时带一个返回值回去
break counter * 2;
}
};
println!("The result is {result}");
}
while循环为条件判断循环。
fn main() {
let mut number = 3;
while number != 0 {
println!("{number}!");
number -= 1;
}
println!("LIFTOFF!!!");
}
for循环在Rust中,基本上只用于迭代器(暂时可以想象成对数组,动态数组等)的遍历
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {element}");
}
}
// 左闭右开区间
for number in 1..4 {
println!("{number}");
}
println!("--");
// 左闭右闭区间
for number in 1..=4 {
println!("{number}");
}
println!("--");
// 反向
for number in (1..4).rev() {
println!("{number}");
}
14.函数
使用 fn 关键字来定义一个函数
fn print_a_b(a: i32, b: char) {
println!("The value of a b is: {a}{b}");
}
fn main() {
print_a_b(5, 'h');
}
15. 闭包(Closure)
闭包是另一种风格的函数。它使用两个竖线符号 || 定义,而不是用 fn () 来定义
// 标准的函数定义
fn add_one_v1 (x: u32) -> u32 { x + 1 }
// 闭包的定义,请注意形式对比
let add_one_v2 = |x: u32| -> u32 { x + 1 };
// 闭包的定义2,省略了类型标注
let add_one_v3 = |x| { x + 1 };
// 闭包的定义3,花括号也省略了
let add_one_v4 = |x| x + 1 ;
fn main() {
let a = 10u32; // 局部变量
fn add_v1 (x: u32) -> u32 { x + a } // 定义一个内部函数
let add_v2 = |x: u32| -> u32 { x + a }; // 定义一个闭包
let result1 = add_v1(20); // 调用函数
let result2 = add_v2(20); // 调用闭包
println!("{}", result2);
}
add_v1 (内部函数) 报错原因
代码中 fn add_v1 虽然定义在 main 内部,但它本质上还是一个普通的函数。
- 机制: Rust 的
fn定义的函数(包括内部函数)是无状态的。它在编译时就是一个独立的指令块,不包含任何指向“定义它的环境”的指针。 - 限制: 它只能访问通过参数传入的变量或者全局静态变量(
static/const) 。 - 现状: 变量
a是main函数栈上的一个局部变量。add_v1无法“看到”或“捕获”这个局部变量a。 - 编译器报错: 编译器会提示
can't capture dynamic environment in a fn item(在 fn 项中无法捕获动态环境)。