Rust基础学习 - 第1天:语法与变量

1. 变量绑定与不可变性

核心概念

  • 变量绑定 : Rust使用let关键字将值"绑定"到变量名上
  • 默认不可变性: Rust变量默认不可变,这是Rust安全理念的基石
  • 可变性声明 : 使用mut关键字显式声明变量可变

为什么默认不可变?

不可变性帮助避免许多常见的编程错误,特别是在并发环境中。这使得代码更安全、更易于推理,也是Rust"无畏并发"承诺的基础。

rust 复制代码
// 不可变变量示例
let x = 5;
// x = 10; // 编译错误: 不能对不可变变量二次赋值

// 可变变量示例
let mut y = 10;
y = 20; // 正确 - y被声明为可变的

变量遮蔽(Shadowing)

与可变性不同,变量遮蔽允许重新使用相同的变量名,但实际上创建了新变量,可以改变类型。

rust 复制代码
let z = 5;        // 第一个z
let z = z + 1;    // 创建新的z,值为6
let z = "hello";  // 再次遮蔽,现在z是字符串类型

2. 基本数据类型

标量类型

整数类型

  • 有符号: i8, i16, i32, i64, i128, isize(指针大小)
  • 无符号: u8, u16, u32, u64, u128, usize(指针大小)
  • 默认类型: i32 - 通常是最快的,即使在64位系统上

整数字面量

rust 复制代码
let decimal = 98_222;    // 下划线作为视觉分隔符
let hex = 0xff;          // 十六进制
let octal = 0o77;        // 八进制
let binary = 0b1111_0000;// 二进制
let byte = b'A';         // 字节(仅用于u8)

浮点类型

  • f32: 单精度浮点
  • f64: 双精度浮点(默认)

布尔类型

  • bool: 值为truefalse
  • 占用1字节空间

字符类型

  • char: 表示Unicode标量值
  • 4字节大小,可表示超出ASCII的值
  • 使用单引号(与字符串的双引号不同)

3. 复合类型

元组(Tuple)

  • 固定长度的不同类型值的组合
  • 一旦声明,大小不可改变
  • 通过解构或索引访问元素
rust 复制代码
let tup: (i32, f64, &str) = (500, 6.4, "Rust");

// 解构获取值
let (x, y, z) = tup;

// 索引访问
let first = tup.0;  // 500

数组(Array)

  • 固定长度的相同类型元素集合
  • 分配在栈上,而非堆上
  • 当需要固定数量元素时比Vec更高效
rust 复制代码
// 类型标注: [类型; 长度]
let arr: [i32; 5] = [1, 2, 3, 4, 5];

// 初始化包含相同值的数组
let zeros = [0; 10];  // 十个0组成的数组

// 访问元素
let first = arr[0];

数组越界检查

Rust在访问数组元素时总是执行边界检查,这与C/C++不同,可以防止缓冲区溢出漏洞。

4. 类型推导与标注

类型推导

Rust拥有强大的类型推导系统,常常不需要显式标注类型。

类型标注语法

rust 复制代码
let x: i32 = 42;
let y: (i32, f64) = (10, 3.14);

5. 实践示例:温度转换程序

下面的例子结合了变量声明、数学运算和格式化输出:

rust 复制代码
fn main() {
    // 摄氏度转华氏度
    let celsius = 25.0;  // 浮点默认为f64
    let fahrenheit = celsius * 9.0 / 5.0 + 32.0;
    
    println!("{}°C = {}°F", celsius, fahrenheit);
    
    // 使用变量遮蔽演示华氏度转摄氏度
    let fahrenheit = 77.0;  // 遮蔽之前的fahrenheit变量
    let celsius = (fahrenheit - 32.0) * 5.0 / 9.0;
    
    println!("{}°F = {}°C", fahrenheit, celsius);
}

这个例子演示了:

  • 浮点数计算
  • 变量遮蔽的实际应用
  • 使用println!宏的格式化输出

6. 代码实现

我们在项目中实现了一个完整的示例,展示了所有这些概念:

rust 复制代码
// src/week1/day1.rs
pub fn run() {
    println!("=== Rust基础学习 - 第1天:语法与变量 ===\n");

    // 变量绑定与不可变性示例
    println!("--- 变量绑定与不可变性 ---");
    let x = 5;
    println!("x的值是: {}", x);

    let mut y = 10;
    println!("y初始值: {}", y);
    y = 20;
    println!("y修改后: {}", y);

    // 变量遮蔽
    let z = 5;
    let z = z + 1;
    let z = z * 2;
    println!("z经过两次遮蔽后的值: {}", z);
    
    // 变量遮蔽允许改变类型
    let spaces = "   ";
    let spaces = spaces.len();
    println!("空格数量: {}", spaces);
    
    // 基本数据类型示例
    println!("\n--- 基本数据类型 ---");
    let a: i32 = 42;
    let b: u64 = 100;
    let c = 256;
    println!("整数: a={}, b={}, c={}", a, b, c);

    // 复合类型示例
    println!("\n--- 复合类型 ---");
    let tup: (i32, f64, &str) = (500, 6.4, "Rust");
    let (x, y, z) = tup;
    println!("解构元组: x={}, y={}, z={}", x, y, z);
    
    // 温度转换示例
    println!("\n--- 温度转换示例 ---");
    let celsius = 25.0;
    let fahrenheit = celsius * 9.0 / 5.0 + 32.0;
    println!("{}°C = {}°F", celsius, fahrenheit);
}

7. 运行结果

8. 学习要点总结

  1. Rust通过默认不可变性提供安全保障
  2. 使用mut显式标记可变变量
  3. 变量遮蔽与可变性是不同的概念
  4. Rust提供丰富的数值类型,包括不同大小的整数和浮点数
  5. 复合类型(元组和数组)有固定长度且不可增长
  6. Rust始终执行边界检查以防止内存安全问题

9. 思考与练习

  1. 尝试编写一个程序,将英寸转换为厘米(1英寸 = 2.54厘米)
  2. 创建一个程序,使用不同的数据类型并尝试进行类型转换
  3. 探索变量遮蔽的更多用例,比如处理字符串操作

1. 英寸转厘米程序

rust 复制代码
fn inch_to_cm() {

    println!("--- 英寸转厘米程序 ---");

    let inches = 10.0;
    let cm = inches * 2.54;

    println!("{} 英寸 = {} 厘米", inches, cm);

    // 读取用户输入的方式(需导入标准库)
    /*
    use std::io;

    println!("请输入英寸值:");
    let mut input = String::new();

    io::stdin()
        .read_line(&mut input)
        .expect("读取输入失败");

    // 将输入字符串转换为浮点数
    let inches: f64 = input.trim().parse()
        .expect("请输入有效的数字");

    let cm = inches * 2.54;
    println!("{} 英寸 = {} 厘米", inches, cm);
    */
}

知识点:

  • 浮点数计算
  • 格式化输出
  • 注释展示如何扩展为接受用户输入的交互式程序
  • 错误处理的简单示例(使用expect)

2. 数据类型转换程序

rust 复制代码
fn type_conversion() {
    println!("--- 数据类型转换示例 ---");
    
    // 整数类型间转换
    let a: i32 = 42;
    let b: i64 = a as i64; // 使用as关键字进行显式转换
    let c: u8 = a as u8;
    
    println!("i32 值 {} 转换为: i64={}, u8={}", a, b, c);
    
    // 浮点数与整数间转换
    let float_num: f64 = 3.99;
    let int_num: i32 = float_num as i32; // 截断小数部分,不是四舍五入
    
    println!("浮点数 {} 转换为整数: {}", float_num, int_num);
    
    // 使用内置方法进行四舍五入等操作
    let rounded = float_num.round() as i32;
    let ceiling = float_num.ceil() as i32;
    let floor = float_num.floor() as i32;
    
    println!("浮点数 {} 的处理: 四舍五入={}, 向上取整={}, 向下取整={}", 
             float_num, rounded, ceiling, floor);
    
    // 字符与整数间转换
    let character = 'A';
    let ascii_value = character as u8;
    
    println!("字符 '{}' 的ASCII值: {}", character, ascii_value);
    
    // 整数转换为字符
    let num_value: u8 = 66;
    let char_from_num = num_value as char;
    
    println!("整数 {} 转换为字符: '{}'", num_value, char_from_num);
    
    // 字符串与数字转换
    let num_str = "42";
    let parsed_num: i32 = num_str.parse().expect("解析失败");
    
    println!("字符串 \"{}\" 解析为数字: {}", num_str, parsed_num);
    
    // 数字转字符串
    let num = 100;
    let num_as_string = num.to_string();
    
    println!("数字 {} 转换为字符串: \"{}\"", num, num_as_string);
}

知识点:

  • as 关键字用于基本类型转换
  • 截断转换的行为(浮点到整数)
  • 浮点数的取整方法
  • 字符与ASCII值的转换
  • 字符串解析(parse方法)
  • 使用to_string()将值转换为字符串

3. 变量遮蔽的字符串操作用例

rust 复制代码
fn string_shadowing() {
    println!("--- 变量遮蔽在字符串处理中的应用 ---");
    
    // 案例1: 空格修剪
    let input = "   hello world   ";
    println!("原始字符串: '{}'", input);
    
    let input = input.trim(); // 遮蔽并去除前后空格
    println!("修剪后: '{}'", input);
    
    // 案例2: 大小写转换
    let input = input.to_uppercase(); // 再次遮蔽并转为大写
    println!("转换为大写: '{}'", input);
    
    let input = input.to_lowercase(); // 再次遮蔽并转为小写
    println!("转换为小写: '{}'", input);
    
    // 案例3: 替换操作
    let input = input.replace("hello", "你好"); // 遮蔽并替换文本
    println!("替换后: '{}'", input);
    
    // 案例4: 字符串解析为数字,保持变量名不变
    let data = "42";
    println!("字符串数据: '{}'", data);
    
    let data: i32 = data.parse().expect("无法解析为整数"); // 遮蔽并改变类型
    println!("解析为整数: {}", data);
    
    let data = data * 2; // 数学运算后再次遮蔽
    println!("乘以2: {}", data);
    
    // 案例5: 构建格式化字符串
    let name = "Rust";
    let year = 2010;
    
    // 使用遮蔽构建复杂字符串
    let info = format!("语言名称: {}", name);
    let info = format!("{}, 发布年份: {}", info, year);
    let info = format!("{}, 年龄: {} 年", info, 2023 - year);
    
    println!("信息: {}", info);
}

知识点:

  • 字符串处理方法的链式操作
  • 变量遮蔽消除了创建多个临时变量的需要
  • 字符串与数值类型间的转换
  • 变量遮蔽允许类型转换,保持相同的变量名
  • 格式化字符串的逐步构建
相关推荐
gregmankiw4 小时前
C#调用Rust动态链接库DLL的案例
开发语言·rust·c#
@一枝梅4 小时前
vue3 vite.config.js 引入bem.scss文件报错
javascript·rust·vue·scss
维维酱12 小时前
Rust - 读写锁 (RwLock)
rust
Source.Liu12 小时前
【PhysUnits】15.17 比例因子模块 (ratio.rs)
rust
UestcXiye13 小时前
Rust 学习笔记:关于智能指针的练习题
rust
维维酱1 天前
Rust - 互斥锁
rust
维维酱1 天前
Rust - 共享状态的并发
rust
ArcX1 天前
从 JS 到 Rust 的旅程
前端·javascript·rust
Humbunklung1 天前
Rust Floem UI 框架使用简介
开发语言·ui·rust