变量和常量
变量声明
在 Rust 中,变量默认是不可变的。这意味着一旦一个变量被赋予了一个值,它就不能再被改变。你可以使用 let
关键字来声明一个变量:
let x = 5;
如果你想声明一个可变变量,你需要在 let
关键字后面加上 mut
关键字:
let mut y = 10; y = 20; // 现在 y 的值为 20
常量声明
常量是不可变的,并且必须在声明时初始化。常量可以使用任何类型,但它们的类型必须能被推断出来或者明确指定。常量通常用于表示不会改变的值。声明常量需要使用 const
关键字:
const MAX_POINTS: u32 = 100_000;
类型注解
虽然 Rust 有自动类型推断的能力,但在某些情况下,你可能需要显式地指定变量的类型。这可以通过类型注解来实现。例如:
let guess: u32 = "42".parse().expect("Not a number!");
在这个例子中,guess
被明确地指定为 u32
类型。
数据类型
基本数据类型
Rust 提供了多种基本数据类型,包括整型、浮点型、布尔型和字符型。
整型
Rust 提供了多种有符号和无符号的整型,每种都有不同的位数。常见的有 i8
, i16
, i32
, i64
, i128
以及 u8
, u16
, u32
, u64
, u128
。例如:
let x: i32 = -10; let y: u32 = 100;
浮点型
Rust 有两种浮点类型:f32
和 f64
。其中 f64
是默认类型。例如:
let pi = 3.141592; let e = 2.71_f32;
布尔型
布尔类型只有两种取值:true
和 false
。例如:
let is_raining = true; let is_sunny = false;
字符型
Rust 使用 char
类型来表示单个 Unicode 字符。字符必须用单引号包围。例如:
let c = 'z'; let z = 'ℤ'; let heart_eyed_cat = '😻';
复合类型
元组
元组是一种将多个不同类型的数据组合在一起的方式。元组中的元素可以是任意类型,但它们的类型和数量在定义时必须确定。例如:
let tup = (500, 6.4, 1); let (x, y, z) = tup; println!("The value of y is: {}", y);
数组
数组是一系列相同类型的值。数组的长度在编译时确定,不能改变。例如:
let a: [i32; 5] = [1, 2, 3, 4, 5]; let b = [3; 5]; // 这是一个包含五个 3 的数组
函数
函数定义
函数在 Rust 中通过 fn
关键字定义。函数可以接受参数,并且可以返回一个值。例如:
fn main() { println!("Hello, world!"); } fn add_one(x: i32) -> i32 { x + 1 }
在这个例子中,add_one
函数接受一个 i32
类型的参数并返回一个 i32
类型的值。
参数和返回值
函数可以接受任意数量的参数,每个参数都需要指明类型。同样,函数也可以返回任意类型的值,返回类型也需要在函数签名中声明。例如:
fn plus_one(x: i32) -> i32 { x + 1 }
控制流
Rust 支持多种控制流语句,如 if
、else
、loop
、while
和 for
循环等。
if 语句
if
语句允许根据条件执行代码块。例如:
-- -------------------- ---- ------- --- ------ - -- -- ------ - - -- - - ---------------- -- --------- -- ---- - ---- -- ------ - - -- - - ---------------- -- --------- -- ---- - ---- -- ------ - - -- - - ---------------- -- --------- -- ---- - ---- - ---------------- -- --- --------- -- -- -- -- ---- -
while 循环
while
循环允许重复执行一段代码直到条件不再满足。例如:
let mut count = 0; while count < 5 { println!("{}", count); count += 1; }
for 循环
for
循环提供了一种遍历集合(如数组或向量)的方法。例如:
let a = [10, 20, 30, 40, 50]; for element in a.iter() { println!("the value is: {}", element); }
结构体和枚举
结构体
结构体是一种用户自定义的数据类型,允许你将一组相关的字段组合在一起。例如:
-- -------------------- ---- ------- ------ ---- - --------- ------- ------ ------- -------------- ---- ------- ----- - -- ----------------- ------- --------- ------- -- ---- - ---- - ------ --------- ------- ----- -------------- -- - - --- ----- - ----------------------------------------------- ---------------------------------
枚举
枚举允许你定义一个类型由一组可能的值组成。例如:
-- -------------------- ---- ------- ---- ------- - ----- ---- - -- ---- -- --- -- -------------- ---------------- ---- ----- - ---- ------- - -- ----------- - -- ------- - - --- - - -------------------------------------- ---------
模块系统
Rust 使用模块系统来组织代码。模块帮助你管理命名空间,并且可以用来封装代码。例如:
-- -------------------- ---- ------- --- -------------- - --- --- ------- - --- -- ----------------- -- - - --- --- ------------------------------- -- ------------- -- --- ------------- - --- ------ --------- - --- ------ ------- --------------- ------- - ---- --------- - --- -- ------------- ----- -- --------- - --------- - ------ -------------------- --------------- ------------------------ - - - --- ---- --------- - ----- ------ - - -- ------------------- - --------------------------- --- --- ---- - ---------------------------------------- ---------- - ---------------------- ------------- ---- -- ----- -------- ------------ --- ------ - ------------------------------- --- ------ - -------------------------------- -
在这个例子中,front_of_house
和 back_of_house
都是模块,hosting
是 front_of_house
的子模块。eat_at_restaurant
函数展示了如何使用这些模块中的类型和函数。
错误处理
Result 类型
Rust 使用 Result
类型来处理错误。Result
是一个枚举,有两种可能的状态:Ok
和 Err
。例如:
-- -------------------- ---- ------- --- -------------- -- ------------------------- -- -------------- --------------- - --- - - ------------------------ --- --- - - ----- - - -------- -- ----- ------ -- ------ ------- -- --- --- - - -------------- ----- --------------------- -- - ----- -- ------ ------ -- ------- - - -- -------- --- --- -- ------------------------------- -- -------------- --------------- - --- --- - - ------------------------- --- --- - - -------------- --------------------- ---- ----- -
在这个例子中,read_username_from_file
函数展示了如何使用 match
来处理 Result
类型的返回值。而 read_username_from_file_short
函数则使用了更简洁的 ?
操作符来处理错误。
泛型
泛型函数
泛型允许你在不指定具体类型的情况下编写代码。这样可以使你的代码更加通用和复用性更高。例如:
-- -------------------- ---- ------- -- ---------- ---------- - ----------- ----- -- - - --- --- ------- - -------- --- ----- -- ----------- - -- ---- - ------- - ------- - ----- - - ------- - -- ------ - --- ----------- - -------- --- --- ---- ---- --- ------ - ---------------------- ------------- ------- ------ -- ---- -------- --- --------- - --------- ---- ---- ----- --- ------ - -------------------- ------------- ------- ---- -- ---- -------- -
在这个例子中,largest
函数接受一个泛型参数 T
,并且要求 T
实现 PartialOrd
和 Copy
特征。这意味着这个函数可以用来找出任何实现了这些特征的类型的最大值。
泛型结构体
你也可以为结构体定义泛型。例如:
-- -------------------- ---- ------- ------ -------- - -- -- -- -- - ------- -------- - -- -------- -- -- - ------- - - ---- ---------- - -- --------------------------- -- --- - --------------- - ---------------------- - - -- ------ - --- - - ----- - -- -- -- -- -- ------------- - ---- ------- --- -- - ----- - -- ---- -- --- -- ------------------ ---- ------- ---- --------------------------- -
在这个例子中,Point
结构体是一个泛型结构体,可以存储任意类型的 x
和 y
坐标。对于特定的 f32
类型,我们还为其定义了一个方法 distance_from_origin
,用于计算原点到该点的距离。
生命周期
生命周期注解
生命周期注解确保引用在其作用域内始终有效。这对于避免悬垂引用非常重要。例如:
-- -------------------- ---- ------- -- -------------- --- ---- -- --- ---- -- --- --- - -- ------- - ------- - - - ---- - - - - -- ------ - --- ------- - ------------------ ------ -- ------- - --- ------- - -------------------- --- ------ - ------------------------- ------------------ ------------- ------- ------ -- ---- -------- - -
在这个例子中,longest
函数接受两个字符串切片引用作为参数,并返回一个引用。生命周期注解 'a
确保返回的引用与输入的引用具有相同的生命周期。
生命周期省略规则
Rust 编译器会尝试应用一些生命周期省略规则,以减少显式生命周期注解的需求。例如:
-- -------------------- ---- ------- -- ------------- ----- -- ---- - --- ----- - ------------- --- --- ------ -- ------------------------ - -- ---- -- -- - - ------ --------- - - ------ - -- ------ - --- --------- - ------------------- -------- -- ---------- ----- -- ------ -- --------- --- ---- - --------------------------- ------------- ----- ---- --- ---- ------ -
在这个例子中,first_word
函数接受一个字符串切片引用,并返回一个字符串切片引用。由于 &str
类型的生命周期是隐式的,所以不需要显式地添加生命周期注解。
Trait
定义 Trait
Trait 是一种定义共享行为的方式。它们类似于 Java 中的接口。例如:
-- -------------------- ---- ------- ----- ------- - -- ---------------- -- ------- - ------ ----------- - --------- ------- --------- ------- ------- ------- -------- ------- - ---- ------- --- ----------- - -- ---------------- -- ------ - ------------ -- -- ------ -------------- ------------ -------------- - - ------ ----- - --------- ------- -------- ------- ------ ----- -------- ----- - ---- ------- --- ----- - -- ---------------- -- ------ - ------------ ---- -------------- ------------- - - -- ------ - --- ------- - ----------- - --------- ---------------------- --- --- ------- --- ---------------- --------- ------------------------- --- ------ ------- ------------------------- -------- ---------------------- --------- --- --------- ---------- -------- --- ---- ---- ------- ------- --- ----------- -- ------------- ------- ---------- ---- --------------------- --- ----- - ----- - --------- ----------------------------- -------- ---------------- ------- -- --- -------- ------- ----- --------- ------ ------ -------- ------ -- ----------- --- ------ ---- ------------------- -
在这个例子中,Summary
Trait 定义了一个 summarize
方法。然后,我们为 NewsArticle
和 Tweet
类型实现了这个 Trait。
组合 Trait
你可以通过在 Trait 中包含其他 Trait 来组合它们。例如:
-- -------------------- ---- ------- --- ------------------ ----- ------------- ------- - -- -------------------- - --- ------ - ----------------- --- --- - ------------- -------------- -------------- - ---- ---------------- - ------------ - ---- ----------- -- --- -------- ---------------- - ------------ - ---- -------------- -------------- - ---- - - ------ ----- - -- ---- -- ---- - ---- ------- --- ----- - -- ---------- -- ---- ------------------------ -- ---------------- - --------- ----- ----- ------- ------- - - ---- ------------ --- ----- -- -- ------ - --- - - ----- - -- --- -- -- -- ------------------ -
在这个例子中,OutlinePrint
Trait 包含了 Display
Trait。因此,任何实现了 OutlinePrint
Trait 的类型也必须实现 Display
Trait。通过这种方式,你可以将多个相关的行为组合在一起,使代码更加模块化和易于理解。
以上就是 Rust 的基本语法概述。希望这些示例和解释能帮助你更好地理解和掌握 Rust 的核心概念。