楼主: yik123
551 0

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

  • 0关注
  • 0粉丝

等待验证会员

学前班

40%

还不是VIP/贵宾

-

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

楼主
yik123 发表于 2025-11-15 17:22:50 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

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

经管之家联合CDA

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

感谢您参与论坛问题回答

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

+2 论坛币

本文围绕 Rust 基础语法规则展开,涵盖变量、数据类型、函数、控制流程等核心概念,还介绍了所有权、结构体、枚举、模式匹配、错误处理、生命周期及重影等内容。Rust 是一种强类型和静态类型的编程语言,变量默认不可变,需要使用

mut
声明,支持自动类型推断或明确指定类型。其独特所有权机制确保内存安全,通过借用与引用实现数据共享,生命周期确保引用有效。结构体可定义自定义类型,枚举描述多种可能状态,模式匹配高效处理枚举值,Result 和 Option 枚举帮助错误处理,重影则允许变量名复用并能改变类型和属性,这些内容共同构成了 Rust 基础且关键的语法规则。 变量、基础类型、函数、注释及控制流程——这些概念几乎在所有编程语言中都是“通用配置”。而在 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
,精度会受到影响,因此语言本身禁止这种操作。 第三行则更有趣——
a
不是变量吗?怎么连值都改不了?这就得说到 Rust 为了“高并发安全”所做的设计了:它从语言层面尽量减少变量值被随意修改的可能性,所以
a
虽然称为变量,但默认是不可变的。不过别误解,这并不意味着
a
不是“变量”,Rust 官方文档中,这种变量就称为“不可变变量”。 为什么这样设计?想想吧,如果程序的一部分代码基于“某个值永远不变”的假设编写,而另一部分代码悄悄改变了这个值,那么前一部分代码很可能无法得到预期的结果。而且这种错误排查起来特别困难,Rust 这样做是为了从源头上减少这类问题。 当然,想让变量能够更改值也很简单,加上
mut
关键字即可。例如这样写:
let mut a = 123;
a = 456;
这样的代码就能正常编译和运行,没有问题。 常量与不可变变量的区别 既然不可变变量不能改变值,那它不就和常量一样了吗?为什么还叫“变量”呢?其实两者之间差异不小。 在 Rust 中,下面这段代码是合法的,尽管编译器可能会警告“变量未被使用”,但能通过编译:
let a = 123;   
let a = 456;
但如果将
a
定义成常量,再这样写就不行了:
const a: i32 = 123;
let a = 456;  // 报错,常量不能这么重新定义
简言之,变量支持“重新绑定”——即同一个名称可以重新表示另一个值,但在重新绑定之前,它的值不能私自更改。这种设计的优点是:编译器可以在每次“绑定”后的代码区域中更精确地推断程序逻辑,减少潜在问题。 此外,虽然 Rust 可以自动判断变量类型,但有时明确指定类型会更加方便。例如:
let a: u64 = 123;
这里明确定义
a
是无符号 64 位整型变量。如果不写类型,Rust 会默认将
a
推断为有符号 32 位整型,这两种类型的取值范围相差很大,后续使用时可能会出现问题。 二、数据类型 之前也提到过,Rust 是静态类型语言——在变量声明时可以明确指定类型,不过大多数时候不需要麻烦,依靠其类型推断功能即可。 常用的基础类型有以下几种:
i32
:32 位带符号整数
u32
:32 位无符号整数
f64
:64 位浮点数
bool
:布尔类型(只有 true 和 false 两个值)
char
:字符类型 举几个例子,一目了然:
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,最后一行表达式的结果就是返回值
}
如果函数不需要返回值,那么返回类型默认是
()
,即“空元组”,这种情况下无需特意写出返回类型。 四、控制流程 控制流就是程序执行的路径,Rust 中常用的有 if 表达式、loop 循环、while 循环和 for 循环。我们逐一来看。 if 表达式

if 表达式用于进行“分支判断”,例如判断一个数值的大小:

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

这里 number 是 7,超过 5,因此会显示“大于等于 5”。

loop 循环

loop 是 Rust 中的“无限循环”,如果不主动终止,它将一直运行。要退出循环,可以使用

break

关键字。例如,编写一个计数器:

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

这段代码执行后,counter 会从 0 增加到 10,之后循环停止。

while 循环

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 独特的内存管理机制,也是其核心特性之一。要理解所有权,需要先了解三个关键概念:所有权(ownership)、借用(borrowing)和引用(reference)。

所有权规则

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

Result<T, E>

是一个枚举,专门用于表示“操作成功”或“操作失败”。T 是成功时返回的值类型,E 是失败时返回的错误类型。其定义大致如下:

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

例如编写一个除法函数,如果除数为 0 则返回错误:

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

就是生命周期标注,它告诉编译器:x、y 这两个引用以及函数的返回值具有相同的生命周期。这样编译器就能确保,返回的引用不会在 x 或 y 被删除后继续使用。

十一、重影(Shadowing)

最后我们讨论“重影”。它与面向对象语言中的“重写”(Override)或“重载”(Overload)完全不同。前面提到的“变量重新绑定”,指的就是重影——简单来说,就是同一个变量名可以被重新使用,表示另一个变量。

例如:

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 枚举,更是让我们能写出更健壮、可维护的代码,避免了很多隐性 bug。

这些基础概念就像搭建房子的砖块,刚开始接触时可能会觉得“规矩有点多”,比如所有权转移、生命周期标注等设计,与其他语言的习惯不太相同。但只要多动手写代码、多琢磨每段代码背后的逻辑,慢慢就能体会到这些设计的巧妙之处。后续再学习 Rust 更复杂的特性(如并发、Trait、泛型等)时,你会发现这些基础打得越牢,上手后续内容就越轻松。因此建议大家把这些基础语法多练几遍,用小例子验证每个知识点,真正吃透它们,再往下进阶就会顺理成章啦!

二维码

扫码加我 拉你入群

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

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

关键词:Javascript calculate Ownership borrowing Reference
相关内容:Rust语法应用

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

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