嘿,大家好!
欢迎来到 Rust 学习的第四天,我参考的是 Steve Klabnik 的《Rust 编程语言》一书。昨天我们做了一个 [猜数字游戏](https://blog.csdn.net/Tory2/article/details/137764707?spm=1001.2014.3001.5501)
,今天我们将深入了解常见的编程概念,比如:
- 变量
- 常量
- 局部变量
- 数据类型
- 函数
那么,我们就开始吧?
变量
用通俗的话说,变量就像是存储值的容器。我们快速看一下它们的特点:
- 变量可以存储不同类型的值,比如:数字、文本或复杂结构
- 每个变量都有一个名称
- 在 Rust 中,默认情况下变量是不可变的,意味着一旦设置了值就不能更改,要使变量可变,使用
mut
关键字 - 你可以明确定义变量将存储的值的类型,但这是可选的
- 变量有限定的作用域,意味着它们只能在代码的某个特定部分访问
例子:
fn main(){
let x = 10; // 不可变变量
let mut y = 15; // 可变变量
println!("X = {}",x);
println!("Y = {}",y);
y = 2;
println!("X = {}",x);
println!("Y = {}",y);
}
常量
与不可变变量类似,常量是不允许更改的值,但有一些区别:
- 常量是固有不可变的,不能使用
mut
关键字 - 它们在编译时初始化
- 常量具有全局作用域,可以从程序的任何地方访问
- 常量需要类型定义
例子:
const VALUE_OF_PI: u32 = 3.1418;
局部变量
就像昨天我们看到的那样,通过遮盖,你可以声明与之前变量相同名称的新变量,新变量将会 覆盖 前一个变量。
例子:
fn main(){
let x = 10;
let x = x - 7;
{
let x = x * 2;
println!("内部作用域中的 X = {}",x);
}
println!("外部作用域中的 X = {}",x);
}
输出:
$ cargo run
内部作用域中的 X = 6
外部作用域中的 X = 3
数据类型
数据类型可以进一步分为两组:标量和复合数据类型。
标量数据类型
标量类型表示一个值,Rust 有 4 种主要标量数据类型:
整数
整数是没有分数部分的数字,我们昨天在猜数字游戏中使用了它,u32
表示无符号 32 位整数
其他类型的整数包括:
有符号的:
- 有符号整数和无符号整数的区别在于数字是否需要有一个 符号,或者它是否只能是正数
- 每个有符号整数可以存储从 -(2^(n — 1)) 到 (2^(n — 1)) — 1 的数字,其中 n 是变体使用的位数
- 例如:i8、i16、i32、i64、i128
无符号的:
- 无符号数总是正数。
- 每个无符号整数可以存储从 0 到
2^n — 1
的数字 - 例如:u8、u16、u32、u64、u128
此外还有 isize
和 usize
,根据程序运行的计算机架构而定。如果程序运行在 32 位架构上,则是 32 位,如果程序运行在 64 位架构上,则是 64 位
整数溢出:
- 计算机使用固定数量的位表示整数,确定它们可以覆盖的范围。
- 在 Rust 中,当算术操作的结果超过数据类型可以表示的最大值时(溢出),它会绕回到最小值并继续计数。
整数溢出示例:
如果你使用的是 8 位整数,范围是从 0 到 255。如果你试图给 255 加 1,在正常的算术中,你会期望得到 256。然而,在 Rust 中,由于溢出,它会回到 0。
浮点数:
Rust 中的浮点数具有分数部分。与整数不同,浮点数始终是 有符号的。有两种类型的浮点数:f32
和 f64
,分别表示 32 位和 64 位大小。
例子:
fn main() {
// 使用 f32
let float_32: f32 = 3.14; // 一个 32 位浮点数
println!("f32 值: {}", float_32);
// 使用 f64
let float_64: f64 = 3.141592653589793; // 一个 64 位浮点数
println!("f64 值: {}", float_64);
// 执行算术操作
let result_f32 = float_32 * 2.0;
let result_f64 = float_64 * 2.0;
// 显示结果
println!("结果 (f32): {}", result_f32);
println!("结果 (f64): {}", result_f64);
}
数字操作
Rust 支持基本的数学运算,如:
- 加法
- 减法
- 乘法
- 除法
- 取余
例子:
fn main(){
let sum = 10+7;
let subtraction = 60-4;
let multiplication = 7 * 7;
let division = 25/5;
let modulus = 13%2;
println!("10 + 7 = {}",sum);
println!("60 - 4 = {}",subtraction);
println!("7 * 7 = {}",multiplication);
println!("25 / 5 = {}",division);
println!("13 % 2 = {}",modulus);
}
布尔类型
与大多数编程语言一样,布尔类型大小为一个字节,可以是 true
或 false
。
例子:
fn main(){
let t = true;
let f: bool = false;
}
字符类型
Rust 的 char
类型是最原始的字母类型,类似于 C 中的 char
。
fn main(){
let z = 'Z';
let x: char = "X";
}
侧面说明:字符用单引号括起来,而字符串用双引号括起来。
复合类型
复合类型可以在一个类型中存储多个值。它们通常是一组标量数据。
元组
在 Rust 中,元组类似于一个混合包,可以包含不同类型的项,允许你按特定顺序组织和组合它们。这是一种将多个值捆绑在一起的简单方法。
元组是不可变的。但是,如果它们声明为可变变量,元组内的元素可能是可变的。
语法
let var_name: (data_type1,data_type2...data_typeN) = (val1,val2...valN);
// 这个元组中的值是可变的
let mut var_name: (data_type1,data_type2...data_typeN) = (val1,val2...valN);
例子
let tup: (i32, f64, u16) = (500,3.141,9);
访问元组中的数据
索引:
索引是指通过其位置或键访问数据结构中的特定元素,如数组或元组。
要使用索引访问元组,我们可以这样做:
println!("{}",tuple_name.index);
例子:
fn main() {
// 创建一个元组
let my_tuple = (42, "hello", 3.14);
// 使用索引访问元素(从零开始)
let first_element = my_tuple.0; // 访问第一个元素(42)
let second_element = my_tuple.1; // 访问第二个元素("hello")
let third_element = my_tuple.2; // 访问第三个元素(3.14)
// 打印访问的元素
println!("第一个元素: {}", first_element);
println!("第二个元素: {}", second_element);
println!("第三个元素: {}", third_element);
}
数组
数组是另一种按顺序存储相同类型数据的方法。Rust 中的数组长度是固定的。
我们使用方括号 []
作为逗号分隔列表来编写数组。
例子:
fn main(){
let a: [i32;5]= [1,2,3,4,5];
}
我们还可以这样做:
fn main(){
let x = [6; 4]; // [6,6,6,6]
}
访问数组元素:
fn main() {
let a: [u32; 6] = [1, 2, 3, 4, 5, 6];
let first: u32 = a[0];
let last: u32 = a[a.len() - 1];
println!("第一个元素 : {}", first); // 1
println!("最后一个元素 : {}", last); // 6
}
函数
从技术上讲,函数的定义是,它是执行特定任务的自包含代码单元,接受输入并产生输出,增强代码结构和可重用性。
main
函数是 Rust 程序的入口点,同样我们可以使用 fn
关键字声明自定义函数来执行特定任务。
在 Rust 中,snake_case
是声明函数和变量名的约定。
例子
fn main(){
println!("主函数");
new_function();
}
fn new_function(){
println!("这是一个自定义函数");
}
输出
$ cargo run
主函数
这是一个自定义函数
参数
通俗地说:参数是传递给函数的输入
技术上来说,参数是函数定义中的一个占位符,参数是你调用函数时提供给函数的实际值或数据。它们与函数中定义的参数的类型和顺序相匹配。
虽然人们往往会将这些词混用。
例子
fn main(){
println!("主函数");
addition(5,9);
}
fn addition(x: i32,y: i32){
println!("{} + {} 的和 = {}",x,y,x+y);
}
输出
$ cargo run
主函数
5 + 9 的和 = 14
语句和表达式
语句是执行特定任务的指令,而表达式则评估为一个值。
例子
fn main(){
let y = 6; // 语句
let x = 5; // 语句
let result = x+y; // 这里的 "x+y" 是一个表达式
}
带有返回值的函数
函数可以在调用时返回一个值。我们必须使用箭头 ->
声
明函数的返回类型。
在 Rust 中,函数的最终表达式是函数的返回值。
例子
fn main(){
println!("主函数");
let sum = addition(5,9);
println!("函数的结果 : {}", sum);
}
fn addition(x: i32,y: i32) -> i32 {
x+y // 返回语句
}
在 Rust 中,返回语句末尾的分号的缺失表示它是要返回的值,这样代码更加明确,减少了冗余。
结论
今天就讲到这里,明天我会深入了解 Rust 中的控制流程。