rust基础(一)

220 阅读10分钟

大家好,我是鱼樱!!!

关注公众号【鱼樱AI实验室】持续分享更多前端和AI辅助前端编码新知识~~

不定时写点笔记写点生活~写点前端经验。

在当前环境下,纯前端开发者可以通过技术深化、横向扩展、切入新兴领域以及产品化思维找到突破口。

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

前端最卷的开发语言一点不为过,三天一小更,五天一大更。。。一年一个框架升级~=嗯,要的就是这样感觉!与时俱进~

注释

// 这是第一种注释方式  
  
/* 这是第二种注释方式 */  
  
/*  
 * 多行注释  
 * 多行注释  
 * 多行注释  
 */

变量

Rust 是强类型语言,但具有自动判断变量类型的能

默认情况下,Rust 中的变量是不可变的,除非使用 mut 关键字声明为可变变量

声明变量,需要使用 let 关键字

变量的值可以"重新绑定",但在"重新绑定"以前不能私自被改变,这样可以确保在每一次"绑定"之后的区域里编译器可以充分的推理程序逻辑

// 变量声明
let x = 5;
// 打印语句
println!("x: {}", x); // x: 5

// 错误的三种
// x = "123";
// x = 1.23; 
// x = 3;


// 可变变量
let mut y = 10;
y += 5;
// 打印语句
println!("y: {}", y); // y: 15

// 变量和常量还是有区别的
let a = 123;   // 可以编译,但可能有警告,因为该变量没有被使用
let a = 456;

数据类型

Rust 的数据类型可以分为基本类型(Primitive Types)和复合类型(Compound Types)两大类

Rust 是静态类型语言,在变量声明时可以显式指定类型,但通常可以依赖类型推断。

  • 基本类型: i32 (32位有符号整数), u32 (32位无符号整数), f64 (64位浮点数), bool (布尔类型), char (字符)
  • 复合类型: 元组(Tuple)、数组(Array)、切片(Slice)、结构体(Struct)、枚举(Enum)

数据类型分类

类型类别类型名称描述
基本类型整数类型i8i16i32i64i128(有符号)
u8u16u32u64u128(无符号)
isizeusize(根据平台决定大小)
基本类型浮点类型f32f64
基本类型布尔类型bool(值为 true 或 false
基本类型字符类型char(表示 Unicode 字符)
复合类型元组(Tuple)一组不同类型的值组合,如 (i32, f64, char)
复合类型数组(Array)固定长度的相同类型元素集合,如 [i32; 5]
复合类型切片(Slice)对数组或字符串的引用,如 &[i32] 或 &str
复合类型结构体(Struct)自定义类型的复合数据结构
复合类型枚举(Enum)多个可能值的类型,如 Option<T> 和 Result<T, E>

对比表

特性基本类型复合类型
组成单一值多个值或不同类型组合
示例i32f64boolchartuplearrayslicestructenum
用途表示简单的数据值表示复杂的数据结构
可变性可变或不可变变量通常需要通过 mut 关键字声明可变性
内存管理通常存储在栈上可能引用堆内存(如 Vec<T>String

数据类型示例:

// 基本类型
let integer: i32 = 10;
let float: f64 = 3.14;
let boolean: bool = true;
let character: char = 'A';

// 元组
let tuple: (i32, f64, char) = (10, 3.14, 'A');

// 数组
let array: [i32; 3] = [1, 2, 3];

// 切片
let slice: &[i32] = &array[..];

// 结构体
struct Point {
    x: i32,
    y: i32,
}

// 枚举
enum Option<T> {
    Some(T),
    None,
}

函数

fn <函数名> ( <参数> ) <函数体>

Rust 函数通过 fn 关键字定义,函数的返回类型通过箭头符号 -> 指定

Rust 不支持自动返回值类型判断!如果没有明确声明函数返回值的类型,函数将被认为是"纯过程",不允许产生返回值,return 后面不能有返回值表达式。

注意: 函数体表达式并不能等同于函数体,它不能使用 return 关键字。

Rust 中定义函数如果需要具备参数必须声明参数名称和类型

// 如果函数没有返回值,类型默认为 ()(即空元组)
fn add(a: i32, b: i32-> i32 {  
    a + b  
}

条件语句

Rust 中的 if 不存在单语句不用加 {} 的规则,不允许使用一个语句代替一个块。尽管如此,Rust 还是支持传统 else-if 语法的

Rust 中的条件表达式必须是 bool 类型

注意:两个函数体表达式的类型必须一样!且必须有一个 else 及其后的表达式块

fn main() {
    let number = 1; 
    if number < 3 { 
        println!("条件为 true"); 
    } else { 
        println!("条件为 false"); 
    } 
}

循环

image.png image.png

Rust 中的循环种类

循环类型语法描述
looploop { ... }无限循环,直到遇到 break 为止
whilewhile condition { ... }条件为 true 时循环执行代码块
forfor item in iterator { ... }遍历一个迭代器(如数组、范围等)
while letwhile let Some(value) = iterator.next() { ... }当模式匹配时持续循环(常用于迭代器)
for 循环结合 Rangefor i in 0..5 { ... }遍历一个范围(如 0..5 表示 0 到 4)

示例代码

1. loop

场景:某个个循环无法在开头和结尾判断是否继续进行循环,必须在循环体中间某处控制循环的进行。如果遇到这种情况,我们经常会在一个 while (true) 循环体里实现中途退出循环的操作

loop 循环可以通过 break 关键字类似于 return 一样使整个循环退出并给予外部一个返回值。

let mut counter = 0;
loop {
    println!("Counter: {}", counter);
    counter += 1;
    if counter == 3 {
        break;
    }
}

2. while

let mut number = 1;
while number != 4 {
    println!("{}", number);
    number += 1;
}
println!("EXIT");

3. for 遍历数组

let arr = [10, 20, 30, 40, 50];
for element in arr.iter() {
    println!("Element: {}", element);
}

4. for 遍历范围

for i in 0..5 {
    println!("i = {}", i);
}

5. while let(用于模式匹配)

let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
    println!("Popped: {}", top);
}

循环语句总结

Rust 提供了多种循环结构,适用于不同的场景:

  • loop:无限循环,手动控制退出。
  • while:根据条件循环。
  • for:遍历迭代器或范围,最常用且安全。
  • while let:结合模式匹配使用,适用于处理 Option 或 Result 类型的迭代。

在 Rust 中,0..10 是一个 范围(Range)  表达式,表示一个左闭右开的区间,即从 0 到 10 的整数序列,不包含 10

含义:

  • 0..10 表示的值是:0, 1, 2, 3, 4, 5, 6, 7, 8, 9

类型:

0..10 的类型是 std::ops::Range<i32>,即 Range 结构体,定义为:

struct Range {
    start: i32,
    end: i32,
}

常见用法:

通常用于 for 循环中遍历数字序列:

for i in 0..10 {
    println!("{}", i);
}

这段代码会打印从 0 到 9 的所有整数。

对比其他范围表达式:

表达式含义包含的值示例
0..10左闭右开区间0, 1, 2, ..., 9
0..=10闭区间(包含两端)0, 1, 2, ..., 10
..10从开始到结束(常用于切片)从 0 到 9
5..从起始值到无穷大(常用于迭代器)5, 6, 7, ...

..小结:

  • 0..10 表示一个从 0 到 10 的范围,不包含 10
  • 常用于 for 循环中遍历数字序列
  • 是 Rust 中非常常见且高效的迭代方式之一

迭代器(Iterator)

Rust 中的迭代器(Iterator)是一种用于遍历集合(如数组、向量、字符串等)的抽象机制,具有高效、安全、灵活的特点。

Rust 中,迭代器通过实现 Iterator trait 来定义

  • .iter():返回集合的不可变引用迭代器。
  • .iter_mut():返回集合的可变引用迭代器。
  • .into_iter():将集合转移所有权并生成值迭代器。

迭代器遵循以下原则:

  • 惰性求值 (Laziness) :Rust 中的迭代器是惰性的,意味着迭代器本身不会立即进行任何计算或操作,直到你显式地请求数据。这使得迭代器在性能上表现良好,可以避免不必要的计算。
  • 所有权和借用检查 (Ownership and Borrowing Checks) :Rust 迭代器严格遵守所有权和借用规则,避免数据竞争和内存错误。迭代器的生命周期与底层数据相关联,确保数据的安全访问。
  • 链式调用 (Chaining) :Rust 迭代器支持链式调用,即可以将多个迭代器方法链接在一起进行组合操作,这使得代码简洁且具有高度可读性。例如,通过使用 .map().filter().collect() 等方法,可以创建复杂的数据处理流水线。
  • 高效内存管理 (Efficient Memory Management) :迭代器避免了不必要的内存分配,因为大多数操作都是惰性求值的,并且在使用时直接进行遍历操作。这对于处理大数据集合尤其重要。
  • 抽象和通用性 (Abstraction and Generality) :Rust 的迭代器通过 Iterator trait 实现抽象和通用性。任何实现了 Iterator trait 的类型都可以在不同的上下文中作为迭代器使用。此设计提高了代码的重用性和模块化。

一、迭代器概念

在 Rust 中,迭代器是惰性求值的(lazy),即只有在真正使用时才会执行。迭代器主要通过 .iter().into_iter().iter_mut() 等方法创建。

方法用途所有权
.iter()不可变借用集合中的每个元素不获取所有权
.into_iter()获取集合所有权,并遍历元素获取所有权
.iter_mut()可变借用集合中的每个元素不获取所有权

常用用法

1. 遍历数组

let a = [10, 20, 30, 40, 50];
for i in a.iter() {
    println!("值为 : {}", i);
}

2. 遍历向量

let v = vec![1, 2, 3];
for num in v.iter() {
    println!("{}", num);
}
// 1
// 2
// 3

3. 遍历范围

for i in 0..5 {
    println!("{}", i);
}

4. 使用 enumerate 获取索引和值

for (index, &value) in a.iter().enumerate() {
    println!("索引: {}, 值: {}", index, value);
}

5. 使用 mapfilter 等函数式操作

let squares: Vec<_> = (1..6).map(|x| x * x).collect();
let evens: Vec<_> = (1..11).filter(|x| x % 2 == 0).collect();

注意事项

注意点说明
迭代器是惰性的如 mapfilter 等不会立即执行,需要调用 collect 或 for 循环才会触发执行
避免多次使用同一个迭代器一旦迭代器被消费(如调用 for 或 collect),就不能再次使用
选择合适的迭代方式根据是否需要所有权选择 iterinto_iteriter_mut
性能优化Rust 的迭代器在编译时会优化为高效的底层代码,接近甚至优于手动循环
不可变 vs 可变迭代器如果需要修改元素,使用 iter_mut() 并注意借用规则

迭代器总结

  • Rust 的迭代器是功能强大且类型安全的工具,适用于各种集合的遍历和处理。
  • 掌握 .iter().into_iter() 和 .iter_mut() 的区别是使用迭代器的关键。
  • 迭代器配合 mapfilterfold 等方法可以写出简洁、函数式的代码。
  • 注意迭代器的惰性求值特性,避免误用导致逻辑错误或性能问题。