Rust 学习笔记 - 变量声明与使用

前言

任何一门编程语言几乎都脱离不了:变量、基本类型、函数、注释、循环、条件判断,这是一门编程语言的语法基础,只有当掌握这些基础语法及概念才能更好的学习 Rust。

变量介绍

Rust 是一种强类型语言,但在声明变量时,不总是需要显式声明类型,这是因为 Rust 的编译器有类型推断系统。当声明一个变量而没有指定类型时,Rust 编译器会根据变量的初始值自动推断出它的类型。

在强类型语言中,每个变量和常量都必须有一个明确的类型,而且类型在编译时就已经确定。Rust 编译器非常严格,不允许不同类型的数据隐式转换。如果需要将一个类型转换为另一个类型,必须使用明确的类型转换方法。这一特性使得 Rust 在编译时能够提供类型检查,有助于避免许多常见的运行时错误。

不可变变量 (Immutable)

与其他编程语言(如:Java、Python、JS)不同,默认情况下 Rust 中的变量是不可变的 (神奇,变量不可变🤔)。

这一特性意味着变量一旦被赋值后,在变量的整个生命周期内它的值就不能被改变,尝试修改一个不可变变量的值会导致编译时错误。

示例:

rust 复制代码
let x = 5;
x = 6; // 这会导致编译错误,因为 x 是不可变的

可变变量 (Mutable)

  • 通过使用 mut 关键字,可以声明一个可变的变量,这样的变量允许其值在后续被修改。
  • 但需要注意,rust 作为强类型语言,修改变量时不允许赋值其他类型的值

示例:

rust 复制代码
let mut x = 5;
x = 6; // 这是允许的,因为 x 是可变的

// error[E0308]: mismatched types
x = 3.1415926; // 3.1415926 是浮点数,x 声明时是整形

变量遮蔽(Shadowing)

变量遮蔽是 Rust 中的一个特性,有些文档或教程将 Shadowing 称为:隐藏重影,它允许在相同作用域中,使用相同的名称声明一个新变量。这个新声明的变量"遮蔽"了先前声明的同名变量。更准确地说,当新变量被引入时,它会使得与之同名的先前变量不再可见,直到新变量离开作用域前,无法访问被遮蔽的变量。这与变量重新赋值不同,因为它实际上是在创建一个全新的变量。

遮蔽的好处是可以重新使用更有意义或适用于当前上下文的变量名,遮蔽通常用于转换值的类型或给变量一个新值,而这样做并不影响原来变量的不可变性。

示例1:

rust 复制代码
let x = 5;
let x = x + 1; // 遮蔽前一个 x 变量
let x = "现在 x 是一个字符串"; // 再次遮蔽,改变了值的类型

示例2:

rust 复制代码
fn main() {
    let x = 5;
    let x = x + 1;

    {
	    // 在使用花括号创建的内部作用域内,变量 `x` 被遮蔽
        let x = x * 2;
        println!("x 在当前作用域的值是: {x}"); // 12
    }
	// 当作用域结束后,内部 shadowing 的作用域也结束了,`x` 又返回到 `6`
    println!("x 在当前作用域的值是: {x}"); // 6
}

常量 (Constants)

  • 常量使用 const 关键字声明,并且它们总是不可变的。
  • 常量必须在声明时就赋值,而且它们的类型必须显式声明。
  • 常量名应该全部大写,否则会报警告。

示例:

rust 复制代码
const MAX_POINT: u32 = 100_000;

不可变变量 与 常量的区别

在 Rust 中,虽然不可变变量和常量都不能在声明后被修改,但它们之间存在几个主要区别:

类型标注

  • 声明常量时,必须显式给出类型标注
  • 不可变变量通常可以依赖 Rust 的类型推断,类型标注是可选的。

示例:

rust 复制代码
// ok!
let x = 1000;
// error: missing type for `const` item
const CONST_VAL = 1000; 

值的赋予时机

  • 常量在编译时被赋值,且必须是一个恒定的表达式,不能是运行时的结果。
  • 不可变变量可以在运行时被初始化,其中的值可以是在运行时才能确定的表达式的结果。

示例1:

rust 复制代码
fn get_val() -> i32 {
    1000
}

fn main() {
	// ok!
    let x = get_val(); 
    // const 不能接收运行时的结果
    // error[E0015]: cannot call non-const fn `get_val` in constants
    const CONST_VAL: i32 = get_val(); 
}

示例2:

rust 复制代码
fn main() {
	// let 允许先声明,后赋值
    let x;
    x = 1000; 

	// error: free constant item without body
	const CONST_VAL: i32; 
	// error[E0070]: invalid left-hand side of assignment
	CONST_VAL = 1000;
}

变量遮蔽

  • 不可变变量可以通过变量遮蔽进行重新赋值
  • 常量无法进行变量遮蔽,相同常量名重复定义时会报错

示例:

rust 复制代码
    let x = 1000;
     // ok!
    let x = "str";

    const CONST_VAL: i32 = 1000;
    //  // error[E0428]: the name `CONST_VAL` is defined multiple times
    const CONST_VAL: &str = "str";

作用域

  • let 关键字用于在局部作用域中声明变量,如函数或代码块内部,而不能用于全局作用域。
  • const 关键字可以用于全局作用域中声明常量,也可以在局部作用域中使用。

示例:

rust 复制代码
const GLOBAL_CONST: i32 = 10; // 全局常量,可以在整个程序中访问

// error: expected item, found keyword `let`
// let x = 1000; // 不允许声明全局变量
fn main() {
    let local_var = 5; // 局部变量,只能在 main 函数内访问
    println!("常量: {}", GLOBAL_CONST);
    println!("局部变量: {}", local_var);
}

fn another_function() {
    // local_var 在这里是不可见的,因为它不在作用域内
    // GLOBAL_CONST 仍然是可见的
    println!("同一个常量: {}", GLOBAL_CONST);
}

结语

本文深入介绍了 Rust 中的变量声明,特别是它独有的不可变变量变量遮蔽特性。相较于其它编程语言,这些概念初看可能会给变量操作带来复杂性。然而,随着使用的深入,这些概念将变得清晰明了,你将发现它们实际上是 Rust 强大功能和安全性的体现,而且并不复杂。

相关推荐
whinc6 小时前
Rust技术周刊 2026年第17周
后端·rust
whinc6 小时前
Rust技术周刊 2026年第18周
后端·rust
hmbbcsm6 小时前
关于transformors库的学习笔记
笔记·学习
xqqxqxxq7 小时前
Java AI智能P图工具技术笔记
java·人工智能·笔记
whinc7 小时前
Rust技术周刊 2026年第16周
后端·rust
FakeOccupational7 小时前
【电路笔记 PCB】Altium Designer : AD20信号完整性(Signal Integrity)分析+单线路传输分析+串扰分析(暂记)
笔记
星辰徐哥7 小时前
Rust异步测试与调试的实践指南
android·java·rust
minglie17 小时前
qemu相关脚本
学习
闪闪发亮的小星星8 小时前
链路预算相关
笔记
古城小栈9 小时前
langchain-rust:高性能Rust LLM应用开发实战
开发语言·rust·langchain