3、Rust基础速通(一):变量与可变性、基本数据类型、函数与闭包、所有权与借用
好,咱们直接切入正题。Rust 这门语言,说实话,一开始上手会觉得有点「别扭」。尤其是从 Python 或 JavaScript 转过来的朋友,可能会被它的「规矩」吓到。但别急,这些规矩背后,都是为了安全和高性能。今天这一章,我带你快速过一遍 Rust 最核心的几个基础概念。你只要把这几个点吃透了,后面写量化策略的底层逻辑,就会非常顺畅。
3.1 变量与可变性:默认不可变
在 Rust 里,变量默认是不可变的。这跟大多数语言不一样。我刚开始写 Rust 时,也经常被编译器怼:「你不能给一个不可变变量赋值两次!」
为什么会这样?说白了,这是 Rust 为了内存安全做的设计。你想想看,如果一个变量到处都能被改,多线程下很容易出问题。Rust 干脆让你默认「锁死」它,除非你主动声明要改。
let x = 5;
// x = 6; // 这行会报错:cannot assign twice to immutable variable
let mut y = 10;
y = 20; // 可以,因为 y 是可变的
mut。这样代码逻辑清晰,也更容易排查 bug。
3.2 基本数据类型:标量与复合
Rust 的数据类型分两大类:标量(Scalar)和复合(Compound)。标量就是单个值,复合是把多个值打包在一起。
标量类型
- 整数:
i32(有符号32位)、u64(无符号64位)等。量化计算中,我常用i64存时间戳,u64存订单ID。 - 浮点数:
f64(双精度)。做价格计算时,f64是标配,精度够用。 - 布尔值:
bool,就是true/false。 - 字符:
char,用单引号,比如'A'。
复合类型
- 元组(Tuple):可以放不同类型的数据。比如
let tup: (i32, f64, u8) = (500, 6.4, 1); - 数组(Array):固定长度,所有元素类型相同。比如
let arr: [i32; 5] = [1, 2, 3, 4, 5];
f32 存价格,结果因为精度不够,导致撮合时出现了「价格漂移」。后来全部换成 f64,问题解决。记住:金融计算,精度就是生命。
3.3 函数与闭包:两种「做事」的方式
函数和闭包,都是用来封装逻辑的。但闭包更灵活,可以捕获环境中的变量。
函数
Rust 的函数用 fn 关键字声明。参数必须标注类型,返回值用 -> 指定。
fn add(a: i32, b: i32) -> i32 {
a + b // 注意:没有分号,这是表达式,作为返回值
}
闭包
闭包用 || 包裹参数,可以省略类型标注。它最大的特点是能「记住」它定义时的环境。
let factor = 1.5;
let multiplier = |x: f64| x * factor; // 闭包捕获了 factor
let result = multiplier(100.0); // 结果是 150.0
3.4 所有权与借用:Rust 的「独门绝技」
所有权(Ownership)是 Rust 最核心的概念。没有它,就没有内存安全。说白了,Rust 通过一套规则,在编译时就决定了谁「拥有」一块内存,以及什么时候释放它。
所有权规则
- 每个值都有一个所有者(owner)。
- 同一时间,一个值只能有一个所有者。
- 当所有者离开作用域,值会被自动释放。
let s1 = String::from("hello");
let s2 = s1; // s1 的所有权转移给了 s2
// println!("{}", s1); // 这行会报错:s1 已经失效
你可能会问:「那我怎么让多个地方都能用同一个数据?」答案是:借用(Borrowing)。
借用:引用与可变引用
借用就是通过 & 符号,借一个变量的引用,而不拿走所有权。
fn calculate_length(s: &String) -> usize {
s.len()
} // 这里 s 离开作用域,但因为是借用,不会释放内存
let s = String::from("hello");
let len = calculate_length(&s);
println!("{} 的长度是 {}", s, len); // 正常,s 的所有权还在
但注意:同一时间,要么只能有一个可变引用,要么只能有多个不可变引用。这是 Rust 防止数据竞争的手段。
知识体系总览
下面这张图,帮你把今天讲的内容串起来。你可以把它当作一个「思维导图」,方便回顾。
好了,这一章的内容就到这里。变量、数据类型、函数闭包、所有权借用,这四个点构成了 Rust 的「地基」。你只要把所有权和借用的逻辑想明白,后面学泛型、生命周期、并发编程,就会轻松很多。