Rust
在 Windows 上自定义 Rust 安装路径
1. 设置环境变量
在 Windows 上,你可以通过设置环境变量来指定 Rust 的安装路径。需要设置以下两个环境变量:
CARGO_HOME:指定 Cargo 的安装目录(包括cargo可执行文件、缓存、配置文件等)。RUSTUP_HOME:指定 Rustup 的安装目录(包括 Rust 工具链、配置文件等)。
方法 1:通过命令提示符临时设置
打开命令提示符(CMD)或 PowerShell,运行以下命令:
set CARGO_HOME=C:\path\to\cargo
set RUSTUP_HOME=C:\path\to\rustup
#或者
cd D:\devel\rust #进入安装的目录
set RUSTUP_HOME=%CD%\.rustup
set CARGO_HOME=%CD%\.cargo方法 2:永久设置环境变量
右键点击“此电脑”或“我的电脑”,选择“属性”。
点击“高级系统设置”。
在“系统属性”窗口中,点击“环境变量”。
在“用户变量”或“系统变量”中,点击“新建”:
变量名:
CARGO_HOME,变量值:C:\path\to\cargo变量名:
RUSTUP_HOME,变量值:C:\path\to\rustup将
C:\path\to替换成你要的安装路径
点击“确定”保存。
2. 安装 Rust
设置好环境变量后,下载并运行 Rust 安装程序:
- 访问 Rust 官方安装页面:https://www.rust-lang.org/tools/install
- 下载
rustup-init.exe。 - 运行
rustup-init.exe,按照提示完成安装。
安装程序会自动检测你设置的环境变量,并将 Rust 安装到指定的路径。
3. 验证安装
安装完成后,打开命令提示符或 PowerShell,运行以下命令验证安装:
rustc --version
cargo --version如果输出了 Rust 和 Cargo 的版本信息,说明安装成功。
示例
假设你想将 Rust 安装到 D:\Rust 目录下:
- 设置环境变量:
CARGO_HOME=D:\Rust\cargoRUSTUP_HOME=D:\Rust\rustup
- 运行
rustup-init.exe完成安装。 - 安装完成后,Rust 工具链会安装在
D:\Rust\cargo和D:\Rust\rustup目录中。
注意事项
路径不要包含空格或特殊字符:尽量使用简单的路径,例如
D:\Rust,避免使用C:\Program Files这样的路径,因为空格可能会导致一些问题。环境变量生效:如果你在安装前设置了环境变量,请确保它们已生效。可以通过以下命令检查:
bashecho %CARGO_HOME% echo %RUSTUP_HOME%移动已安装的 Rust:如果你已经安装了 Rust,可以通过手动移动
%USERPROFILE%\.cargo和%USERPROFILE%\.rustup目录到新路径,并更新环境变量。
在 Linux/macOS 系统 上自定义 Rust 安装路径
设置
CARGO_HOME和RUSTUP_HOME环境变量CARGO_HOME:用于指定 Cargo 的安装目录(包括cargo可执行文件、缓存、配置文件等)。RUSTUP_HOME:用于指定 Rustup 的安装目录(包括 Rust 工具链、配置文件等)。
你可以在安装 Rust 之前设置这些环境变量,或者在安装后通过修改环境变量来移动这些目录。
安装 Rust
在设置好环境变量后,使用
rustup安装 Rust。bashexport CARGO_HOME=/custom/path/to/cargo export RUSTUP_HOME=/custom/path/to/rustup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh这将把 Rust 工具链安装到你指定的路径中。
验证安装
安装完成后,你可以通过以下命令验证 Rust 是否安装成功:
bashsource $CARGO_HOME/env rustc --version cargo --version
示例
假设你想将 Rust 安装到 /opt/rust 目录下:
export CARGO_HOME=/opt/rust/cargo
export RUSTUP_HOME=/opt/rust/rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh安装完成后,Rust 工具链将会安装在 /opt/rust/cargo 和 /opt/rust/rustup 目录中。
注意事项
- 如果你已经安装了 Rust,并且想要移动安装目录,你需要手动将
~/.cargo和~/.rustup目录移动到新的位置,并更新环境变量。 - 确保你设置的环境变量在每次启动终端时都能生效。你可以将这些环境变量添加到你的 shell 配置文件(如
~/.bashrc、~/.zshrc等)中。
echo 'export CARGO_HOME=/custom/path/to/cargo' >> ~/.bashrc
echo 'export RUSTUP_HOME=/custom/path/to/rustup' >> ~/.bashrc
source ~/.bashrc这样,每次启动终端时,环境变量都会自动设置好。
命令
项目运行:
cargo run高性能运行:
cargo run --release检查一下代码能否编译通过:
cargo check项目构建:
cargo build该命令将下载相关的依赖库,等下载成功后,再对 package 和下载的依赖进行一同的编译构建。
更新依赖:
cargo update # 更新所有依赖
cargo update -p regex # 只更新 “regex”清理cargo缓存
cargo clean
cargo build #重新构建变量可变性
使用mut关键字声明
let mut x = 5;使用下划线开头忽略未使用的变量
fn main() {
let _x = 5;
let y = 10;
}Cargo.toml 和 Cargo.lock
Cargo.toml 和 Cargo.lock 是 cargo 的核心文件,它的所有活动均基于此二者。
Cargo.toml是cargo特有的项目数据描述文件。它存储了项目的所有元配置信息,如果 Rust 开发者希望 Rust 项目能够按照期望的方式进行构建、测试和运行,那么,必须按照合理的方式构建Cargo.toml。Cargo.lock文件是cargo工具根据同一项目的toml文件生成的项目依赖详细清单,因此我们一般不用修改它,只需要对着Cargo.toml文件撸就行了。
宏
内置宏
Rust 还提供了一些内置宏,它们简化了常见的编程任务:
vec![]: 创建一个Vec<T>向量。format!(): 格式化字符串。println!(): 打印到标准输出。assert!(): 断言条件为真。panic!(): 引发 panic。include!(): 包含另一个文件的内容。concat!(): 连接常量字符串。env!(): 获取环境变量。dbg!(): debug 输出
可变引用
字符串切片:是按字节算,一个中文算三个字节
Rust 中的字符是 Unicode 类型,因此每个字符占据 4 个字节内存空间,但是在字符串中不一样,字符串是 UTF-8 编码,也就是字符串中的字符所占的字节数是变化的(1 - 4)
String类型
在 Rust 中,String 是一个动态大小、可增长的字符串类型
- 内存管理:
String是堆分配的,拥有自己的内存空间- 可以动态增长、修改
- 当
String超出作用域时,会自动释放内存
- 特点:
- 使用 UTF-8 编码
- 可以通过
.push_str()、.push()等方法修改 - 拥有所有权,可以转移所有权
- 可以通过
.clone()深拷贝
- 创建方式:
// 从字面量创建
let s1 = String::from("hello");
let s2 = "hello".to_string();
// 创建空字符串
let mut s3 = String::new();- 常用方法:
.len(): 获取字节长度.push_str(): 追加字符串.push(): 追加单个字符.pop(): 移除最后一个字符.insert(): 插入单个字符char.insert_str(): 插入字符串字面量rustfn main() { let mut s = String::from("Hello rust!"); s.insert(5, ','); println!("插入字符 insert() -> {}", s); s.insert_str(6, " I like"); println!("插入字符串 insert_str() -> {}", s); }
- 与
&str的转换:
let s: String = "hello".to_string();
let slice: &str = &s; // 借用主要用途是需要拥有和修改字符串的场景,而 &str 更适合只读引用。
将 String 类型转为 &str 类型
fn main() {
let s = String::from("hello,world!");
say_hello(&s);
say_hello(&s[..]);
say_hello(s.as_str());
}
fn say_hello(s: &str) {
println!("{}",s);
}实际上这种灵活用法是因为 deref 隐式强制转换,具体我们会在 Deref 特征进行详细讲解。
连接 (Concatenate)
1、使用 + 或者 += 连接字符串
使用 + 或者 += 连接字符串,要求右边的参数必须为字符串的切片引用(Slice)类型。其实当调用 + 的操作符时,相当于调用了 std::string 标准库中的 add() 方法,这里 add() 方法的第二个参数是一个引用的类型。因此我们在使用 + 时, 必须传递切片引用类型。不能直接传递 String 类型。+ 是返回一个新的字符串,所以变量声明可以不需要 mut 关键字修饰。
示例代码如下:
fn main() {
let string_append = String::from("hello ");
let string_rust = String::from("rust");
// &string_rust会自动解引用为&str
let result = string_append + &string_rust;
let mut result = result + "!"; // `result + "!"` 中的 `result` 是不可变的
result += "!!!";
println!("连接字符串 + -> {}", result);
}代码运行结果:
连接字符串 + -> hello rust!!!!引用和借用
在 Rust 中,引用(Reference)和借用(Borrowing)是密切相关的概念,但并不完全相同:
- 借用(Borrowing)是一种概念:
- 指通过引用访问数据,而不获取其所有权
- 分为可变借用(
&mut)和不可变借用(&) - 是 Rust 所有权系统的核心机制
- 引用(Reference)是具体的语法实现:
- 使用
&符号创建 - 允许你引用某个值,但不获取其所有权
示例代码:
fn main() {
let x = 5;
let y = &x; // y 是 x 的引用,这里也是一次借用
let mut s = String::from("hello");
let r1 = &s; // 不可变借用
let r2 = &s; // 可以同时有多个不可变借用
let r3 = &mut s; // 可变借用(互斥)
}借用的规则:
- 在同一作用域中,要么有一个可变引用,要么有多个不可变引用
- 引用必须总是有效的
总之,借用是一个概念,而引用是实现这个概念的具体语法机制。
可变引用同时只能存在一个不过可变引用并不是随心所欲、想用就用的,它有一个很大的限制: 同一作用域,特定数据只能有一个可变引用
可变引用与不可变引用不能同时存在
悬垂引用(Dangling References)
悬垂引用也叫做悬垂指针,意思为指针指向某个值后,这个值被释放掉了,而指针仍然存在,其指向的内存可能不存在任何值或已被其它变量重新使用。在 Rust 中编译器可以确保引用永远也不会变成悬垂状态:当你获取数据的引用后,编译器可以确保数据不会在引用结束前被释放,要想释放数据,必须先停止其引用的使用。
让我们尝试创建一个悬垂引用,Rust 会抛出一个编译时错误
为什么&str 是字符串切片类型
&str 被称为字符串切片(string slice)主要是因为它的内存表示和行为特征:
- 内存结构
// &str 本质上是一个胖指针(fat pointer),包含两部分:
// 1. 指向字符串数据的指针
// 2. 字符串的长度
struct StringSlice {
ptr: *const u8, // 指向字符串起始位置的指针
len: usize, // 字符串长度
}- 切片特性
let s = "hello world";
let part1: &str = &s[0..5]; // 获取 "hello"
let part2: &str = &s[6..]; // 获取 "world"- 特点解释
- 可以从原始字符串创建部分引用
- 不拷贝数据,只是引用原始内存
- 长度和起始位置是确定的
- 与数组切片类似
let arr = [1, 2, 3, 4, 5];
let slice = &arr[1..3]; // 类比字符串切片- 为什么叫"切片"
- 可以从原始字符串"切"出一部分
- 保留原始数据的引用
- 不创建新的内存空间
示例:
fn main() {
let s = String::from("hello world");
let hello: &str = &s[0..5]; // 切片引用
let world: &str = &s[6..]; // 另一个切片
}切片本质上是对连续内存区间的引用,提供了一种高效、零开销的部分访问方式。
str和&str的关系
在 Rust 中,str 和 &str 的关系是这样的:
str(字符串类型):- 是一个没有大小的动态大小类型(DST, Dynamically Sized Type)
- 本身不能直接使用,总是需要通过引用来使用
- 代表一个 UTF-8 编码的字符串序列
&str(字符串切片):- 是
str类型的引用 - 实际上是对
str的借用 - 包含两个部分: a. 指向字符串数据的指针 b. 字符串的长度
- 是
示例代码解释:
// 字面量是 &str 类型
let s: &str = "hello world";
// 不能直接使用 str 类型
// let invalid: str = "this won't work"; // 编译错误
// 总是需要使用引用
fn takes_slice(slice: &str) {
println!("{}", slice);
}关键点:
str本身是不完整的类型,只能通过&str来使用&str是最常见的字符串类型,用于字符串字面量和借用- 当你需要一个可以修改的字符串时,使用
String
这种设计反映了 Rust 对内存安全和所有权的严格控制,确保在编译时就能捕获潜在的内存使用问题。