news 2026/6/10 17:19:19

Rust 入门详解:所有权、引用与借用、结构体、trait(接口)等详尽指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Rust 入门详解:所有权、引用与借用、结构体、trait(接口)等详尽指南

Rust 入门详解:所有权、引用与借用、结构体、trait(接口)等详尽指南 🚀

目标:帮助新手小白理解 Rust 的核心概念(所有权、借用、引用、生命周期、结构体、trait、智能指针等)并通过可运行的代码示例掌握实战要点。文档按主题分块,便于学习与查阅。💡


目录

  1. 所有权(Ownership)与移动(Move)
  2. Copy 与 Clone 的区别
  3. 引用与借用(References & Borrowing)
  4. 可变借用与借用规则(& vs &mut)
  5. 生命周期(Lifetimes)和借用检查器
  6. 字符串、切片和集合的所有权示例
  7. 结构体(Struct)、枚举(Enum)与方法(impl)
  8. trait(接口)与泛型(Generics)
  9. trait object 与动态分发(dyn)
  10. 智能指针 & 共享/并发所有权(Box / Rc / Arc / RefCell / Mutex)
  11. 常见错误 / Borrow checker 报错示例与修复方案
  12. 练习与进阶阅读

1) 所有权(Ownership)与移动(Move) ✅

  • Rust 的核心规则:每个值有一个所有者(owner);同一时间内值只能有一个所有者;当所有者离开作用域时值被释放(Drop)。
  • 移动(move):将所有权从一个变量转移到另一个变量(对堆分配类型,如StringVec等),源变量不再可用。

示例:

fnmain(){lets1=String::from("hello");// s1 拥有堆上的数据lets2=s1;// move:s1 的所有权被移动到 s2// println!("{}", s1); // 错误:s1 已经被移动,不能再使用println!("{}",s2);}

解释要点:

  • 对于堆数据(如String),赋值会移动所有权而不是深拷贝。
  • 对于简单标量(整数、布尔),Rust 实现了Copytrait,赋值会按位复制,不会移动所有权。

2) Copy 与 Clone 的区别 🔁

  • Copy:按位复制(仅适合小的、固定大小、无需析构逻辑的类型,如i32boolchar)。复制时不调用drop,不会使原变量失效。
  • Clone:显式深拷贝(可能需要堆分配),需要调用clone()。可能有运行时成本。

示例:

fnmain(){letx=5;// i32: Copylety=x;// x 仍然可用println!("x = {}, y = {}",x,y);lets1=String::from("hi");lets2=s1.clone();// 深拷贝println!("s1 = {}, s2 = {}",s1,s2);}

建议:尽量避免不必要的clone(),优先通过引用借用数据。


3) 引用与借用(References & Borrowing)🔧

  • 借用分为不可变借用(&T)与可变借用(&mut T)。
  • 借用不会转移所有权,只是临时“借用”访问数据。

示例:

fnmain(){lets=String::from("hello");letlen=calculate_length(&s);// 借用 &s,不取得所有权println!("len = {}",len);}fncalculate_length(s:&String)->usize{s.len()}

解释:

  • &s是不可变借用,函数不能修改s
  • 借用不会触发析构(Drop)当函数返回。

4) 可变借用与借用规则(& vs &mut)📏

规则:

  • 在同一时间,对某个值可以有多个不可变借用 OR 只有一个可变借用(且不能同时存在不可变借用)。
  • 借用的作用域不应超过值的生命周期。

可变借用示例:

fnmain(){letmuts=String::from("hello");change(&muts);println!("{}",s);// "hello, world"}fnchange(s:&mutString){s.push_str(", world");}

错误示例(不可变 & 可变同事存在)

fnmain(){letmuts=String::from("hello");letr1=&s;// 不可变借用letr2=&s;// 另一个不可变借用letr3=&muts;// 错误:同时存在可变借用和不可变借用}

要点:限制借用范围,避免同时存在冲突借用。


5) 生命周期(Lifetimes)和借用检查器 🕒

  • Rust 使用生命周期注解(如'a)来帮助编译器验证引用不会变成悬垂引用。
  • 通常编译器能推导生命周期,但在函数返回引用或结构体持有引用时需要显式注解。

示例(错误):

// 错误:不能返回指向局部变量的引用fninvalid()->&String{lets=String::from("hello");&s// s 在函数结束时被销毁,返回引用悬垂}

正确用法(返回传入引用的一部分):

fnlongest<'a>(x:&'astr,y:&'astr)->&'astr{ifx.len()>y.len(){x}else{y}}

结构体持有引用的例子:

structImportantExcerpt<'a>{part:&'astr,}fnmain(){letnovel=String::from("Call me Ishmael. Some text...");letfirst_sentence=novel.split('.').next().expect("no sentence");leti=ImportantExcerpt{part:first_sentence};}

要点:生命周期注解说明引用之间的关系,不影响程序运行时行为。


6) 字符串、切片和集合的所有权示例 🧵

  • String:可变,堆分配,拥有所有权。
  • &str:字符串切片,借用的数据视图(静态字符串或String的一部分)。

切片示例:

fnmain(){lets=String::from("hello world");lethello=&s[0..5];// &str:借用 s 的一部分println!("{}",hello);}

集合示例(Vec 移动):

fnmain(){letv=vec![1,2,3];letv2=v;// move// println!("{:?}", v); // 错误:v 被移动println!("{:?}",v2);}

若需要共享数据,使用引用或Rc/Arc


7) 结构体(Struct)、枚举(Enum)与方法(impl)🔧

定义与方法示例:

#[derive(Debug, PartialEq)]structRectangle{width:u32,height:u32,}implRectangle{fnnew(width:u32,height:u32)->Self{Self{width,height}}fnarea(&self)->u32{self.width*self.height}fnscale(&mutself,factor:u32){self.width*=factor;self.height*=factor;}}fnmain(){letmutrect=Rectangle::new(10,20);println!("area = {}",rect.area());rect.scale(2);println!("scaled area = {}",rect.area());}

枚举(enum)用于构造代数数据类型,常与模式匹配match联合使用。

enumMessage{Quit,Move{x:i32,y:i32},Write(String),}fnprocess(msg:Message){matchmsg{Message::Quit=>println!("quit"),Message::Move{x,y}=>println!("move {}, {}",x,y),Message::Write(s)=>println!("write: {}",s),}}

8) trait(接口)与泛型(Generics)⚙️

  • trait 定义行为接口(类似其它语言的接口)。
  • 泛型和 trait bound 可实现高度复用代码。

示例:

traitSummary{fnsummarize(&self)->String;fnsummarize_default(&self)->String{String::from("(Read more...)")}}structNews{headline:String,location:String,}implSummaryforNews{fnsummarize(&self)->String{format!("{}, ({})",self.headline,self.location)}}fnnotify(item:&implSummary){// trait bound 写法 1println!("Breaking: {}",item.summarize());}fnnotify2<T:Summary>(item:&T){// 泛型约束写法println!("Breaking2: {}",item.summarize());}

9) trait object 与动态分发(dyn)

  • &impl Trait(或T: Trait)通常是静态分发(编译时单态化)。
  • &dyn Trait是 trait object(动态分发),运行时通过虚表调用方法,允许不同类型在运行时统一处理。

示例:

fnnotify_dyn(item:&dynSummary){println!("dyn: {}",item.summarize());}

10) 智能指针 & 共享/并发所有权(Box / Rc / Arc / RefCell / Mutex)🧠

  • Box<T>:将数据放到堆上,单一所有者。
  • Rc<T>:引用计数(单线程)。
  • Arc<T>:原子引用计数(多线程)。
  • RefCell<T>:允许在运行时进行可变借用检查(单线程),实现“内部可变性”。
  • Mutex<T>:互斥锁,用于多线程可变访问。

示例(Rc<RefCell<T>>):

usestd::rc::Rc;usestd::cell::RefCell;fnmain(){letdata=Rc::new(RefCell::new(5));letd1=Rc::clone(&data);*d1.borrow_mut()+=1;println!("{}",data.borrow());// 6}

多线程示例(Arc<Mutex<T>>):

usestd::sync::{Arc,Mutex};usestd::thread;fnmain(){letcounter=Arc::new(Mutex::new(0));letmuthandles=vec![];for_in0..10{letc=Arc::clone(&counter);handles.push(thread::spawn(move||{letmutnum=c.lock().unwrap();*num+=1;}));}forhinhandles{h.join().unwrap();}println!("counter = {}",*counter.lock().unwrap());}

注意:仅在需要共享可变所有权时使用这些类型。


11) 常见错误 / Borrow checker 报错示例与修复方案 ⚠️

示例与修复:

  1. 返回指向局部变量的引用(E0515) → 返回拥有所有权的值或让引用来自于输入参数。
  2. 同时存在不可变借用与可变借用(E0502) → 避免重叠借用,限制作用域。
  3. move 后使用值(E0382) → 使用引用或clone()(尽量避免 clone)。
  4. RefCell运行时借用冲突会 panic → 在使用RefCell时遵守借用规则,或改用其它策略。

12) 练习与进阶阅读 📚

练习题:

  • 实现fn longest<'a>(x: &'a str, y: &'a str) -> &'a str并写单元测试。
  • Rc<RefCell<T>>实现一个共享计数器,并演示两个持有者修改它。
  • 实现一个Rectangle,为其派生Debug,PartialEq,Clone,并编写示例代码。

进阶阅读:

  • 《The Rust Programming Language》(The Rust Book)
  • Rust 官方文档:std::rc,std::sync,std::cell等。

✅ 小结:

  • 所有权与借用是 Rust 安全与并发性的基石;理解它们对写出正确高效的 Rust 程序至关重要。

如果你希望,我可以把所有示例拆成examples/可运行示例,并帮你验证它们能否编译运行(我也可以把文档放到docs/下或仓库根目录)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 0:46:33

小红书种草文案构思:女性创作者分享AI数字人使用心得

小红书种草文案构思&#xff1a;女性创作者分享AI数字人使用心得 在小红书刷到第37个“自律vlog”时&#xff0c;我突然意识到——原来不是我不想更新内容&#xff0c;而是每次面对镜头&#xff0c;都要花两小时化妆、打光、重拍五遍才敢发出去。作为一位专注分享职场穿搭和情绪…

作者头像 李华
网站建设 2026/6/10 15:43:56

Discord频道筹备中:国际化社区建设提上日程

Discord频道筹备中&#xff1a;国际化社区建设提上日程 在教育机构需要为同一课程制作多语言版本视频、客服中心希望快速生成不同形象的AI讲解员、内容创作者面对海量短视频需求却人手不足的今天&#xff0c;一个能“说人话”的数字人系统不再只是炫技的玩具&#xff0c;而是实…

作者头像 李华
网站建设 2026/6/10 15:10:14

C# 12顶级语句部署最佳实践,解决生产环境5大常见故障

第一章&#xff1a;C# 12顶级语句概述与部署背景C# 12 引入了更简洁的顶级语句&#xff08;Top-Level Statements&#xff09;语法&#xff0c;旨在简化应用程序入口点的编写方式。开发者无需再手动定义类和 Main 方法&#xff0c;即可直接在程序文件中编写执行逻辑&#xff0c…

作者头像 李华
网站建设 2026/6/10 14:26:25

私有化部署报价咨询:企业客户可联系科哥定制方案

HeyGem 数字人视频生成系统&#xff1a;企业级私有化部署的技术实践 在内容为王的时代&#xff0c;企业对高质量视频的需求呈指数级增长。无论是线上课程、产品宣传&#xff0c;还是客服播报和品牌推广&#xff0c;传统真人出镜拍摄模式正面临人力成本高、制作周期长、难以规模…

作者头像 李华
网站建设 2026/6/9 23:11:10

M4A苹果用户友好:HeyGem接受iTunes导出的音频文件

HeyGem原生支持M4A&#xff1a;打通苹果用户音频创作“最后一公里” 在数字内容爆发式增长的今天&#xff0c;教育机构、自媒体创作者和企业培训部门正面临一个共同挑战&#xff1a;如何快速、低成本地生成高质量的口型同步视频。传统的真人拍摄与后期制作流程不仅耗时耗力&…

作者头像 李华
网站建设 2026/6/10 13:45:41

一文读懂 GPU:从 “图形专家” 到 “计算多面手”

提到电脑里的核心硬件&#xff0c;很多人首先会想到 CPU&#xff08;中央处理器&#xff09;&#xff0c;但在游戏画面渲染、AI 训练、影视特效制作等场景中&#xff0c;另一个 “隐形功臣” 正发挥着不可替代的作用 —— 它就是 GPU&#xff08;图形处理器&#xff09;。从让我…

作者头像 李华