本文为从 Solidity 或 JavaScript 背景转向 Rust 的开发者解析了 Rust 中常见的语法特性,包括所有权与引用(& 和 *)、mut 可变性、泛型(<T>)、unwrap() 和 ? 运算符,帮助理解其逻辑并适应 Rust 的编程范式。
对于来自 Solidity 或 JavaScript 背景的开发者,Rust 中的 &
、mut
、<T>
、unwrap()
和 ?
等语法可能显得陌生甚至有些别扭。本章将逐一解析这些语法的含义及其背后的逻辑。
如果初次阅读时无法完全理解,不必担心。你可以随时返回本文复习这些概念。
要理解 &(引用)和 *(解引用),首先需要认识 Rust 中的“可复制类型”。所谓可复制类型,指的是内存占用固定且较小、复制开销低的数据类型,包括:
这些类型之所以“可复制”,是因为它们的大小已知且较小,复制成本可忽略。
反之,像 Vec(向量)、String(字符串)和结构体(struct)这样的大小不固定或可能很大的类型,则属于“不可复制类型”。
来看这段 Rust 代码:
pub fn main() {
let a: u32 = 2;
let b: u32 = 3;
println!("{}", add(a, b)); // a 和 b 被复制到 add 函数
let s1 = String::from("hello");
let s2 = String::from(" world");
println!("{}", concat(s1, s2)); // 无法编译
}
// add 和 concat 的实现此处省略
对于 a 和 b,Rust 会自动复制这两个 32 位整数到 add 函数,总共仅 64 位开销。但对于字符串 s1 和 s2,如果也直接复制,可能涉及大量数据(例如 1GB 的字符串),性能会显著下降。
Rust 要求开发者明确指定如何处理不可复制类型,而不是像动态语言那样隐式复制。这正是所有权机制的核心。
对于不可复制类型(如字符串、向量、结构体),变量一旦被赋值,就“拥有”该值的所有权。所有权转移后,原变量无法再访问该值。看下面例子:
let s1 = String::from("abc");
let s2 = s1; // s2 接管 "abc" 的所有权,s1 失效
// println!("{}", s1); // 编译失败:s1 已失去所有权
println!("{}", s2); // 正常运行:s2 拥有 "abc"
修复方法有两种:使用引用(&)或克隆(clone)。
通过 &,我们可以让变量“借用”数据而不转移所有权:
pub fn main() {
let s1 = String::from("abc");
let s2 = &s1; // s2 借用 s1 的值,不拥有
println!("{}", s1); // 正常:s1 仍拥有值
println!("{}", s2); // 正常:s2 查看 s1 的值
}
关键点:& 表示只读引用(借用),允许其他变量访问数据而不改变其所有权。
如果需要独立副本,可以使用 clone:
fn main() {
let mut message = String::from("hello");
let mut y = message.clone(); // y 获得 messag...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!