楼主: 慕菲橙。
84 0

[其他] 【新】Rust入门:基础语法应用 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

80%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0.0253
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
30 点
帖子
2
精华
0
在线时间
0 小时
注册时间
2018-11-1
最后登录
2018-11-1

楼主
慕菲橙。 发表于 2025-12-3 15:33:14 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

本文系统介绍了 Rust 编程语言的核心语法结构,内容涵盖变量定义、基础数据类型、函数声明、控制流程等通用编程要素,同时深入讲解了所有权机制、结构体与枚举的使用、模式匹配、错误处理策略、生命周期管理以及变量重影等独具特色的语言特性。Rust 属于静态强类型语言,其变量默认为不可变状态,若需修改必须通过特定关键字显式声明。该语言支持类型自动推断,也允许开发者手动指定类型。

Rust 所有权系统是保障内存安全的关键设计,它通过借用和引用机制实现数据共享,同时借助生命周期规则确保所有引用在有效范围内使用。结构体可用于构建自定义复合类型,而枚举则适用于表示多种可能的状态或类型。结合模式匹配,能够高效地处理复杂的条件分支逻辑。标准库中的 Result 与 Option 枚举极大增强了程序对异常情况的处理能力。此外,变量重影(shadowing)机制允许同名变量重新绑定,并可变更其类型与属性,这一特性在提升代码灵活性的同时保持了安全性。

mut

上述机制共同构成了 Rust 语言坚实且严谨的基础语法体系,为编写高性能、高安全性的系统级程序提供了有力支撑。

变量、基本类型、函数、注释以及控制流——这些元素几乎存在于所有主流编程语言中,属于编程的“基础设施”。在 Rust 中,它们不仅是入门必学内容,更是贯穿整个开发过程的核心工具。尽早掌握这些基础知识,有助于后续学习更加顺畅,显著提升学习效率与实践能力。

一、变量

需要明确的是,Rust 是一门静态强类型语言,具备强大的类型推断能力,能够在大多数情况下自动识别变量类型。这种智能推导容易让人误以为它是弱类型语言,但实际上恰恰相反。

一个关键特点是:Rust 中的变量默认是不可变的。如果希望变量值可以被修改,则必须使用

mut

关键字进行声明。例如:

let a = 123;       // 不可变变量,值定了就改不了
let mut b = 10;  // 可变变量,后续能改它的值

从语法上看,变量声明必须以

let

开头。对于熟悉 JavaScript 的开发者而言,这种写法较为常见;而对于仅接触过 C 语言的程序员来说,可能会感到陌生。

一旦某个变量被

let a = 123;

修饰,以下三段代码均无法通过编译:

a = "abc";
a = 4.56; 
a = 456;

第一行出错的原因在于:

a

在初始化为整数 123 后,其类型已被固定为整型。尝试将字符串赋值给它会引发类型不匹配错误。

第二行的问题在于 Rust 不允许可能导致精度丢失的隐式类型转换。浮点数 4.56 赋值给整型变量会造成信息截断,因此被语言本身禁止。

第三行的情况更为特殊——即使

a

被称为“变量”,也无法更改其值。这源于 Rust 对并发安全的设计理念:通过限制变量的可变性,减少因意外修改导致的逻辑错误。虽然名为“变量”,但默认状态下实为“不可变变量”(immutable variable),这也是官方文档中的正式称呼。

这样的设计有何意义?设想某段代码基于“某个值永不改变”的前提编写,若其他部分擅自修改该值,前者的行为将变得不可预测,且此类问题难以调试。Rust 通过默认不可变机制,从根本上降低这类风险。

当然,若确实需要可变变量,只需添加

mut

关键字即可。如下代码便可顺利编译运行:

let mut a = 123;
a = 456;

常量与不可变变量的区别

既然不可变变量也不能修改值,那它和常量有何不同?为何仍称为“变量”?其实两者存在本质差异。

以下代码在 Rust 中是合法的(尽管编译器可能提示未使用变量,但仍可通过编译):

let a = 123;   
let a = 456;

但如果将

a

定义为常量后再执行类似操作,则会报错:

const a: i32 = 123;
let a = 456;  // 报错,常量不能这么重新定义

简言之,变量支持“重绑定”(rebinding),即同一标识符可在作用域内多次代表不同的值或类型,但在每次绑定期间自身不可更改。这种机制使编译器能在每个绑定区间更精确地分析程序行为,从而优化检查逻辑,预防潜在 bug。

虽然类型推断非常便利,但在某些场景下显式标注类型更具优势。例如:

let a: u64 = 123;

此处明确指定

a

为无符号 64 位整型。若省略类型声明,Rust 将默认推断为有符号 32 位整型,两者取值范围差异显著,可能引发运行时问题。

二、数据类型

如前所述,Rust 是静态类型语言,变量类型通常在声明时确定。得益于强大的类型推断系统,多数情况下无需显式标注。

常见的基本数据类型包括:

i32

:32 位有符号整数

u32

:32 位无符号整数

f64

:64 位双精度浮点数

bool

:布尔类型,仅包含 true 和 false 两个值

char

:Unicode 字符类型

通过以下示例可直观理解其用法:

let x: i32 = 42;          // 32位有符号整数,值是42
let y: f64 = 3.14;        // 64位浮点数,值是3.14
let is_true: bool = true; // 布尔类型,值是true
let letter: char = 'A';   // 字符类型,值是'A'

三、函数

在 Rust 中定义函数需使用

fn

关键字,函数返回类型则通过箭头符号

->

来声明。

例如,一个简单的加法函数可写作:

fn add(a: i32, b: i32) -> i32 {
    a + b  // 函数返回值,不用写return,最后一行表达式的结果就是返回值
}

当函数不返回任何有意义的值时,其返回类型默认为

()

,即空元组(unit type)。此时无需显式写出返回类型。

四、控制流

控制流决定了程序执行的路径顺序。Rust 提供了多种控制结构,主要包括 if 表达式、loop 循环、while 循环和 for 循环,下面逐一介绍。

if 表达式

在 Rust 中,if 表达式用于实现“分支判断”逻辑,常用来根据条件执行不同的代码块。例如,可以用来判断一个数值的大小关系:

let number = 7;
if number < 5 {
    println!("小于 5");
} else {
    println!("大于等于 5");
}

在这个例子中,变量 number 的值为 7,大于 5,因此程序会输出“大于等于 5”。

Rust 提供了多种循环结构来处理重复性任务,其中最基础的是 loop 循环——它是一种无限循环,除非显式中断,否则将持续运行。要退出循环,可以使用 break 关键字。

break

下面是一个利用 loop 实现计数器的例子:

let mut counter = 0;
loop {
    counter += 1;          // 每次循环让计数器加1
    if counter == 10 {     // 当计数器等于10时
        break;             // 退出循环
    }
}

该程序将使 counter 从 0 开始递增,直到达到 10 后跳出循环。

另一种常见的循环是 while 循环,适用于“当条件成立时持续执行”的场景。一旦条件不再满足,循环即终止。

比如实现一个简单的倒计时功能:

let mut number = 3;
while number != 0 {       // 只要number不等于0,就继续循环
    println!("{}!", number);
    number -= 1;          // 每次循环让number减1
}

运行结果会依次打印出“3!”、“2!”、“1!”,当 number 减至 0 时,循环结束。

for 循环则特别适合用于遍历集合或范围类型的数据。相比手动管理循环变量,for 更加安全且简洁。

例如遍历一个整数区间:

for number in 1..4 {       // 遍历1到3(注意:1..4是左闭右开,不包含4)
    println!("{}!", number);
}

这段代码会依次输出“1!”、“2!”、“3!”,语法清晰,不易出错。

五、所有权(Ownership)

所有权机制是 Rust 独有的内存管理方式,也是其核心特性之一。理解这一概念需要掌握三个关键点:所有权、借用与引用。

在 Rust 中,每个数据值都有唯一的“所有者”,也就是持有该值的变量。同一时间只能有一个所有者存在,不能共享拥有权。当所有者离开其作用域(如函数结束或代码块退出),其所拥有的值会被自动释放,从而避免内存泄漏。

示例如下:

let s1 = String::from("hello");
let s2 = s1; // 这里s1的所有权被“转移”给了s2,s1再也不能用了
// println!("{}", s1); // 这里编译会报错,因为s1已经没有这个值的所有权了

如果只是想临时访问某个值而不获取其所有权,就可以通过“借用”来实现。借用允许你使用引用指向数据,而不会转移控制权。引用通过 & 符号创建。

&

例如,编写一个计算字符串长度的函数时,可以通过借用避免所有权被转移:

fn main() {
    let s = String::from("hello");
    let len = calculate_length(&s);  // 这里用&s,就是“借用”s的值,不拿所有权
    println!("The length of '{}' is {}.", s, len); // 用完还能正常用s,没问题
}

fn calculate_length(s: &String) -> usize {
    s.len() // 函数里只能用s的值,不能改它,也拿不到所有权
}

六、结构体(Structs)

结构体用于定义自定义的数据类型,能够将多个不同类型的数据字段组合在一起,非常适合描述具有多个属性的对象。

比如定义一个表示用户的结构体:

struct User {
    username: String,    // 用户名,字符串类型
    email: String,       // 邮箱,字符串类型
    sign_in_count: u64,  // 登录次数,无符号64位整型
    active: bool,        // 是否活跃,布尔类型
}

// 创建一个具体的用户实例
let user1 = User {
    username: String::from("someusername"),
    email: String::from("someone@example.com"),
    sign_in_count: 1,
    active: true,
};

这样创建的 user1 变量就是 User 类型,包含了完整的用户信息,结构清晰,易于维护。

七、枚举(Enums)

枚举用于定义一个值可能属于多种类型中的一种情况。与结构体不同,它不强调包含多个字段,而是更擅长表达“选项”类的逻辑。

例如,定义 IP 地址的类型(支持 IPv4 和 IPv6):

enum IpAddrKind {
    V4,  // IPv4类型
    V6,  // IPv6类型
}

// 创建枚举实例
let four = IpAddrKind::V4;  // four是IpAddrKind::V4类型
let six = IpAddrKind::V6;   // six是IpAddrKind::V6类型

这种方式能明确区分不同类型的 IP 地址,在后续处理中减少歧义和错误。

八、模式匹配(match)

match 是 Rust 中非常强大的流程控制工具,类似于其他语言中的 switch,但功能更为强大。它可以精确匹配枚举的各种变体,并执行对应的操作。

比如定义一个表示硬币种类的枚举,并写一个函数计算其面值:

enum Coin {
    Penny,   // 1美分硬币
    Nickel,  // 5美分硬币
    Dime,    // 10美分硬币
    Quarter, // 25美分硬币
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,    // 匹配到Penny,返回1
        Coin::Nickel => 5,   // 匹配到Nickel,返回5
        Coin::Dime => 10,    // 匹配到Dime,返回10
        Coin::Quarter => 25, // 匹配到Quarter,返回25
    }
}

调用此函数时,传入不同的 Coin 实例即可返回相应的数值,逻辑清晰直观。

九、错误处理

Rust 通过两种主要的枚举类型来进行错误处理:Result<T, E>Option<T>,它们帮助开发者显式地处理可能出现的问题,防止程序崩溃。

Result 枚举用于表示操作的结果可能是成功或失败。其中 T 表示成功时返回的值类型,E 表示错误类型。其基本定义如下:

Result<T, E>
enum Result<T, E> {
    Ok(T),  // 成功,里面存着成功的值
    Err(E), // 失败,里面存着错误信息
}

例如实现一个安全的除法函数,当除数为零时返回错误信息:

fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err(String::from("Division by zero")) // 除数为0,返回错误信息
    } else {
        Ok(a / b) // 计算成功,返回结果
    }
}

Option 枚举则用于表示“存在值”或“不存在值”的状态,有效避免空指针异常。

Option<T>

比如实现一个从数组中获取指定索引元素的函数:

fn get_element(index: usize, vec: &Vec<i32>) -> Option<i32> {
    if index < vec.len() {
        Some(vec[index]) // 索引合法,返回“有值”,里面存着数组元素
    } else {
        None // 索引越界,返回“没值”
    }
}

调用该函数时,可以明确知道是否成功获取到元素,无需猜测或假设。

十、所有权与借用的生命周期

前面介绍了借用和引用的概念,但还有一个重要问题:如何确保引用始终有效?避免出现“悬垂引用”(即引用了已被释放的内存)?这就引入了“生命周期”的概念。

Rust 使用生命周期标注来保证引用的安全性,通常以 'a 这样的形式表示。虽然大多数情况下编译器能自动推断,但在涉及多个引用时仍需显式标注。

例如,实现一个返回两个字符串中较长者的函数:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

其中的 'a 标注说明参数 xy 以及返回值的生命周期一致,确保返回的引用不会超出原始数据的作用域。

'a

十一、重影(Shadowing)

“重影”是指使用相同名称重新声明变量的行为,这与面向对象语言中的“重写”或“重载”完全不同。在 Rust 中,变量可以通过再次使用 let 关键字进行“遮蔽”,实现对同一名称的复用。

例如:

fn main() {
    let x = 5;
    let x = x + 1;  // 重新绑定x,现在x是6
    let x = x * 2;  // 再一次重新绑定x,现在x是12
    println!("The value of x is: {}", x); // 打印结果是12
}

程序运行后输出结果为:“The value of x is: 12”。

需要注意的是,重影与“可变变量赋值”是两个不同的概念。重影指的是使用相同的名称来代表一个新的变量,这个新变量可以拥有不同的类型、可变性以及数值;而可变变量赋值仅允许修改变量的值,其数据类型和是否可变的属性则保持不变。

例如,以下代码将会引发编译错误:

let mut s = "123"; // s是可变字符串变量
s = s.len();       // 报错!不能给字符串变量赋整型值

在这个例子中,变量 s 最初被定义为字符串类型,即使它被声明为可变变量,使用

mut

也无法将一个整型值

s.len()

赋值给它——因为类型不兼容。这种操作属于类型变更,只有通过重影才能实现,而普通的可变变量无法做到这一点。

回顾整个学习过程,我们已经系统地掌握了 Rust 最核心的基础语法内容。从变量的可变性控制,到各类数据类型的明确划分;从函数的编写方式,到条件与循环等控制结构的应用;再到 Rust 特有的所有权机制、借用规则以及生命周期管理;还包括结构体和枚举等自定义类型的设计——这些知识点并非孤立存在,而是共同构建了 Rust 语言在安全性和性能上的坚实基础。

例如,变量默认不可变这一设计,结合所有权系统,本质上是从语言层面帮助开发者预防内存泄漏和并发访问冲突等问题。而重影机制与可变变量之间的区别,以及模式匹配的强大表达能力,则体现了 Rust 在保证严谨的同时,也兼顾了使用的灵活性。

此外,通过 Result 和 Option 枚举进行错误处理的方式,使得程序能够更清晰地应对异常情况,显著提升了代码的健壮性与可维护性,减少了潜在的隐性缺陷。

这些基础知识就如同建造房屋所用的砖石。初学时可能会觉得限制较多,比如所有权转移的规则或显式的生命周期标注,与其他编程语言的习惯有所不同。但只要坚持动手实践,深入理解每一行代码背后的原理,就能逐渐领悟这些设计背后的深意。

当后续学习更高级的主题(如并发编程、Trait 系统、泛型编程等)时,扎实的基础会大大降低理解难度。因此,建议大家多加练习这些基本语法,通过小规模示例逐一验证各个概念,彻底掌握后再进入下一阶段的学习,这样进阶之路才会更加顺畅自然。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Javascript calculate Ownership Variable Division
相关内容:Rust语法应用

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-5 12:12