当前位置: 首页 > news >正文

趣味学RUST基础篇(高级特征)

章鱼小新的家族是忍者世家,小新掩人耳目的身份是一家火锅店老板,平时用的都是“基础忍术”——变量、函数、控制流,就像他每天吃零食、看动感超人一样普通。但有一天,他发现爸爸的书房里有本闪着金光的书,上面写着:“仅限忍者高手开启”——这就是《Rust 高级特性秘籍》!

第一页:暗影忍术——“不安全 Rust” (Unsafe Rust)

秘籍上画着一个戴着黑色面罩的小新,旁边写着:“此处危险!进入须谨慎!

“当你需要突破常规忍术的限制时,可使用此术。但代价是,你必须自己保证安全,忍者大师(编译器)不再保护你!”

小新明白了:Rust 平时像一个超级严格的老师,时刻说“不许越界!不许空指针!”。但“不安全 Rust”就像打开了“开发者模式”,允许小新直接操作内存、调用 C 语言写的术法,或者做一些“危险动作”。

小新笔记

“这招威力巨大,但一不小心就会‘Segmentation Fault’(忍术反噬)!除非万不得已,否则还是乖乖听话比较好。”

第二页:忍者契约进阶——“高级 Trait”

秘籍翻到“忍者契约”章节,小新发现契约还能这么玩!

  • 关联类型(Associated Types):
    就像给契约加了个“通用装备槽”。比如“忍者必须携带一种武器”,但没规定是手里剑还是苦无。每个忍者(实现者)自己决定带啥,但必须带一种。

  • 默认参数(Default Type Parameters):
    “如果没特别说明,就默认带手里剑。”——省事!

  • 完全限定语法(Fully Qualified Syntax):
    当小新同时继承了“动感超人粉丝”和“蜡笔小新粉丝”两个契约,都叫 watch_tv(),怎么办?
    这时就得说清楚:“我要用动感超人粉丝watch_tv()!”——这就是完全限定。

  • 父契约(Supertraits):
    “想成为‘高级忍者’,你必须先是个‘基础忍者’!”——契约也能有继承关系。

  • Newtype 模式
    小新把自己最喜欢的“巧克力饼干”包装成一个新类型 YummyCookie,这样他就不会和普通的“饼干”搞混了,还能给它加上专属技能,比如“自动飞向嘴巴”!

第三页:神秘符文——“高级类型”

秘籍上画满了奇怪的符文:

  • 类型别名(Type Aliases):
    给长名字的类型起个外号!比如把 Result<String, Box<dyn Error>>MyResult,写起来省力多了。

  • 永不返回的类型(Never Type !):
    一种神秘的“黑洞”类型,代表“这招一出,世界终结”——比如 panic!() 或无限循环。它不返回任何值,因为程序已经“死了”。

  • 动态大小类型(DSTs):
    有些类型大小在编译时不知道,比如 str(字符串切片)或 Trait。它们必须被“装进盒子里”(比如 &strBox<dyn Trait>)才能使用,就像把幽灵关进符咒里。

第四页:忍术卷轴——“高级函数与闭包”

  • 函数指针(Function Pointers):
    小新可以把一个忍术(函数)的名字记在卷轴上,然后让别人按卷轴执行。比如 let f = 动感光波; f();

  • 返回闭包
    更厉害的是,小新可以现场画一个“临时忍术卷轴”(闭包),然后把它交给别人用。但要注意,这个卷轴可能依赖现场的查克拉(变量),所以得用 Box 包起来寄出去。

第五页:自动绘符术——“宏” (Macros)

这是秘籍最炫酷的一页!宏就像“自动绘符机器”。

小新只要说:“我要一个能打印三次‘动感超人’的术!”
然后机器“咔咔咔”自动画出:

println!("动感超人!");
println!("动感超人!");
println!("动感超人!");

宏在代码编译前就自动帮你生成代码,比函数更灵活,能做函数做不到的事。但它的语法有点像魔法咒语,学起来要花点功夫。

秘籍最后一页:忍者守则

“这些高级忍术,平时用得少,但关键时刻能救命。记住:

  • 不安全代码,非必要不用。
  • ,别滥用,否则代码会变得像乱码。
  • 其他高级特性,是为了解决特定难题而生。

现在,你已窥见 Rust 的全貌。去吧,年轻的忍者,用这些知识,守护你的代码世界!”

小新合上秘籍,眼睛闪闪发亮:“原来 Rust 这么酷!下次写作业……不,下次写游戏,我要用‘宏’来自动生成一百个‘动感光波’!”


章鱼小新的“忍者契约”进阶课:高级 Trait 大揭秘!

小新最近迷上了“动感超人”和“蜡笔小新”两个粉丝俱乐部。这两个俱乐部都要求会员会“看动画片”和“收集卡片”。小新心想:“要是能一次加入两个俱乐部多好!”

于是,他打开了他的《Rust 忍者秘籍》,翻到了“高级忍者契约(Advanced Traits)”这一章。


第一课:专属装备槽——关联类型(Associated Types)

秘籍上画着一个“万能忍具袋”,上面写着:Item

“忍者契约可以声明一个‘装备槽’,但不指定具体带啥。每个忍者自己决定!”

trait 忍者装备 {type 武器; // 这就是“装备槽”!fn 使用武器(&self) -> Self::武器;
}// 小新选择带“动感光波”
struct 小新;
impl 忍者装备 for 小新 {type 武器 = String; // 装备槽里放“字符串”fn 使用武器(&self) -> String {"动感光波!!!".to_string()}
}// 爸爸选择带“扳手”
struct 爸爸;
impl 忍者装备 for 爸爸 {type 武器 = i32; // 装备槽里放“整数”(代表扳手数量)fn 使用武器(&self) -> i32 {1 // 挥一下扳手}
}fn main() {let 小新 = 小新;println!("小新使用武器:{}", 小新.使用武器());let 爸爸 = 爸爸;println!("爸爸使用武器:{}", 爸爸.使用武器());
}

小新笔记

“太方便了!每个忍者都能用自己的武器,但都遵守同一个‘使用武器’的规矩。就像不同粉丝俱乐部,都能‘看动画’,但看的动画可能不同!”

第二课:默认选项——默认类型参数(Default Type Parameters)

小新发现,大多数忍者都喜欢带“手里剑”。秘籍说:

“可以在契约里写:‘如果没特别说明,就默认带手里剑!’”

trait 忍者装备<T = 手里剑> { // <T = 手里剑> 就是默认值!fn 投掷(&self, 武器: T);
}struct 手里剑;

这样,如果小新想用默认的手里剑,直接实现就行:

impl 忍者装备 for 小新 {fn 投掷(&self, _: 手里剑) {println!("嗖!手里剑飞出去!");}
}

但如果他想用香蕉皮当武器,也可以覆盖默认值:

impl 忍者装备<香蕉皮> for 小新 { // 明确指定 T 是 香蕉皮fn 投掷(&self, _: 香蕉皮) {println!("啪!敌人滑倒了!");}
}fn main() {//调用let 手里剑 = 手里剑;小新.投掷(手里剑);
}

小新笔记

“默认选项真省事!大多数情况用默认的,特殊需求再改,完美!”


第三课:名字打架了怎么办?——完全限定语法(Fully Qualified Syntax)

问题来了!小新同时加入了“动感超人粉丝”和“蜡笔小新粉丝”两个俱乐部,两个俱乐部都要求会员会 watch_tv()

trait 动感超人粉丝 {fn watch_tv(&self) {println!("看动感超人!正义必胜!");}
}trait 蜡笔小新粉丝 {fn watch_tv(&self) {println!("看蜡笔小新!好开心!");}
}impl 动感超人粉丝 for 小新 {}
impl 蜡笔小新粉丝 for 小新 {}let 小新 = 小新;// 小新. watch_tv(); // 编译器懵了:到底看哪个?!

编译器:“我也不知道该执行哪个 watch_tv 啊!”

这时,秘籍教了小新“完全限定语法”——说出全名!

fn main() {// 明确指定:我要用“动感超人粉丝”这个契约的 watch_tv!<小新 as 动感超人粉丝>::watch_tv(&小新);// 或者,我要用“蜡笔小新粉丝”的!<小新 as 蜡笔小新粉丝>::watch_tv(&小新);
}
第四课:进阶忍者的门槛——父契约(Supertraits)

秘籍上写着:“想成为‘高级忍者’,你必须先是个‘基础忍者’!”

这就是“父契约”(Supertrait)。

// 先定义“基础忍者”契约
trait 基础忍者 {fn 跑酷(&self);
}// “高级忍者”契约说:想实现我,必须先实现“基础忍者”!
trait 高级忍者: 基础忍者 { // 冒号后面就是“父契约”!fn 隐身(&self);
}

这意味着,任何想成为“高级忍者”的人,必须先学会“跑酷”,再学“隐身”。

struct 忍者小新;// 必须先实现父契约!
impl 基础忍者 for 忍者小新 {fn 跑酷(&self) {println!("小新翻了个跟头!");}
}// 再实现高级契约
impl 高级忍者 for 忍者小新 {fn 隐身(&self) {println!("小新……消失了?(其实躲沙发底下了)");}
}

小新笔记

“这就像游戏里,想学‘火球术’,必须先点满‘基础魔法’技能树!合理!”


第五课:包装大师——Newtype 模式

小新有 100 块钱,但他想区分“零花钱”和“压岁钱”,虽然它们都是 i32 类型。

秘籍说:“用 Newtype 模式!给类型套个‘马甲’!”

struct 零花钱(i32);
struct 压岁钱(i32);let 我的零花钱 = 零花钱(50);
let 我的压岁钱 = 压岁钱(100);// 这样就不会搞混了!
// my_allowance + my_gift_money; // 错误!类型不同,不能相加!

更厉害的是,小新可以给“零花钱”加专属技能:

impl 零花钱 {fn 买零食(&self) {if self.0 > 10 {println!("买一包巧克力饼干!");} else {println!("只能买泡泡糖了……");}}
}

小新笔记

“太有用了!把普通类型包装一下,就有了自己的身份和技能!就像把普通石头涂上颜色,变成‘动感石头’!”


章鱼小新的“魔法符咒”课:高级类型大揭秘!

在上完“高级忍者契约”(Traits)的课程后,小新发现《Rust 忍者秘籍》还有一章叫“高级符咒(Types)”。他好奇地翻开,发现里面全是些奇奇怪怪的符号和咒语。

“这些符咒有什么用呢?”小新挠着头问自己。


第一课:马甲与外号——Newtype 模式 vs 类型别名

秘籍上画了两个相似但不同的瓶子:

  • 瓶子A:贴着标签的药水瓶(Newtype 模式)
  • 瓶子B:写着便签的普通杯子(类型别名)

1. 贴标签的药水瓶(Newtype 模式)

“当你需要一个全新的、独立的‘身份’时,就用这个瓶子。它虽然装的是普通水,但贴上‘隐身药水’的标签后,就成了独一无二的宝贝!”

小新明白了:

struct 隐身药水(i32); // 一个元组结构体,给 i32 套了个“马甲”
struct 解药(i32);let 我的药水 = 隐身药水(5);
let 我的解药 = 解药(5);// my_potion + my_antidote; // 错误!编译器说:你不能把“隐身药水”和“解药”相加!

即使它们内部都是 i32,但因为“身份”不同,就不能混用。这能防止小新不小心把自己的“零花钱”当成“压岁钱”花掉!

2. 写着便签的杯子(类型别名 - Type Alias)

“当你只是觉得名字太长太麻烦,想取个‘外号’时,就用这个杯子。”

type 零花钱 = i32; // 给 i32 取个外号叫“零花钱”let x: i32 = 5;
let y: 零花钱 = 5;println!("x + y = {}", x + y); // 完全没问题!因为“零花钱”就是“i32”的外号

小新笔记

“Newtype 是‘变身’,类型别名是‘起外号’。变身后的我(小新)和蜡笔小新是两个人;但‘小新’和‘野原新之助’说的是同一个人!”


第二课:黑洞符咒——Never 类型 (!)

秘籍上画了一个漆黑的洞,旁边写着:!

“这是‘黑洞符咒’,代表‘此处无物,程序已终结’。任何东西掉进去都会消失,包括函数的返回值。”

小新看到一个例子:

fn 发动终极技() -> ! { // 返回类型是 `!`panic!("动感光波……失败了!世界毁灭!");
}

这个函数永远不会正常返回(因为它直接让程序崩溃了),所以它的“返回类型”是一个“不存在的类型”。

为什么有用?

想象小新在玩“猜数字游戏”,如果输入错误,他就“跳过这一轮”:

let guess = match input.trim().parse() {Ok(num) => num,Err(_) => continue, // continue 的“值”就是 `!`
};

continue 不会返回一个数字,它直接跳回循环开头。所以 Rust 知道,guess 的类型只能是 num 的类型(比如 u32),完全没问题!

小新笔记

! 就像游戏里的‘Game Over’画面。一旦出现,游戏结束,没有‘下一关’可言。”


第三课:幽灵与盒子——动态大小类型 (DSTs)

秘籍最后一页画着一个“幽灵”和一个“封印盒”。

“有些东西,大小不固定,就像幽灵一样无法捉摸。你不能直接拿着幽灵,必须把它关进‘盒子’里!”

小新想了想,“一段话”就是字符串。单独的 str 类型大小未知(因为每句话长短不同),所以不能这样写:

let s: str = "Hello!"; // 错误!编译器不知道该分配多大空间

正确做法是把它放进“盒子”:

let s: &str = "Hello!"; // &str 是“引用”,包含地址和长度,大小固定!
let s: Box<str> = "Hello!".into(); // 或者用智能指针 Box

同样,trait 也是一种“能力”,大小未知,也必须放进“盒子”:

let t: &dyn MyTrait = &some_object; // &dyn Trait
let t: Box<dyn MyTrait> = Box::new(some_object); // Box<dyn Trait>

小新笔记

“原来如此!幽灵(DST)必须被‘引用’(&) 或 ‘盒子’(Box) 封印才能使用。否则它们会满屋子乱飘,把程序搞乱!”


章鱼小新的“忍术卷轴”课:函数指针与返回闭包大揭秘!

小新已经学会了写基础的忍术(函数)和现场画符的临时忍术(闭包)。但今天,秘籍翻开了一章更酷的内容:“如何把忍术当成物品传递?如何制造一个能不断生成新忍术的‘忍术工厂’?


第一课:忍术的名字 vs. 忍术本身——函数指针 (fn) 与函数项 (Function Item)

小新一直以为“忍术”就是写在卷轴上的咒语。但秘籍说:

“每个忍术都有两个身份:一个是它的‘名字’,另一个是它‘实际的动作’。”

想象一下:

  • 动感光波() 是一个具体的忍术动作。
  • 动感光波 (不带括号)是这个忍术的“名字”或“地址”。

就像你可以把“动感超人”的海报贴在墙上,也可以让动感超人本人(动作)来你家。

1. 函数指针 (fn) —— 指向忍术的箭头

小新可以创建一个“指向忍术的箭头”(函数指针),然后让别人按箭头执行。

// 定义两个忍术
fn 动感光波() {println!("动感光波!!!");
}fn 臀部炸弹() {println!("扭啊扭……轰!!!");
}// 小新制作了一个“忍术选择器”,里面装的是“指向忍术的箭头”
let mut 当前忍术: fn() = 动感光波; // fn() 是函数指针类型当前忍术(); // 执行:动感光波!!!当前忍术 = 臀部炸弹; // 箭头现在指向“臀部炸弹”
当前忍术(); // 执行:扭啊扭……轰!!!

2. 函数项 (Function Item) —— 忍术的“快照”

而像 let f = 动感光波; f(); 这样的代码,用的是“函数项”,它更像是忍术的一个“快照”。通常情况下,Rust 会自动帮你处理函数项和函数指针的转换,所以小新平时没觉得有啥区别。

小新笔记

“函数指针就像遥控器上的按钮,按下去就执行对应的忍术。我可以随时换按钮(换忍术)!”


第二课:忍术工厂——返回闭包

这是最神奇的一课!小新要学习如何制造一个“忍术生成机”(返回闭包的函数)。

问题是:闭包很特别,每个闭包都是独一无二的“定制符咒”,它们的类型连编译器在编译前都看不清长什么样。

所以,你不能这样写:

fn 制造笑声机器() -> Fn(String) -> String { // 错误!编译器不知道具体是哪个闭包类型|s| format!("{} 哈哈哈!", s)
}

那怎么办?秘籍教了两招:

方法一:装进“封印盒”——使用 Box<dyn Trait>

把生成的闭包装进一个“智能盒子”(Box)里,并告诉盒子:“这里面是个会笑的符咒!”(dyn Fn)。

fn 制造笑声机器() -> Box<dyn Fn(String) -> String> {Box::new(|s| format!("{} 哈哈哈!", s)) // 把闭包装进 Box 返回
}let 笑声机器 = 制造笑声机器();
println!("{}", 笑声机器("小新")); // 输出:小新 哈哈哈!

方法二:模板忍术——使用泛型和 impl Trait

如果小新知道这个“忍术生成机”生产的都是同一类忍术,他可以用“模板”来描述。

// T 是一个未知的类型,但它必须是个“会笑的符咒”
fn 制造笑声机器<T>(笑的方式: T) -> impl Fn(String) -> String 
where T: Fn(&str) -> String,
{move |s| format!("{} {}", s, 笑的方式(&s))
}// 使用
let 幽默机器 = 制造笑声机器(|_| "嘿嘿嘿".to_string());
println!("{}", 幽默机器("小新")); // 输出:小新 嘿嘿嘿

这里 impl Fn(String) -> String 的意思是:“我返回一个东西,它实现了 Fn 这个能力,具体是啥类型?别管,反正你能像调用函数一样用它就行!”

小新笔记

“返回闭包就像开一家‘表情包生成店’。每个客人(调用者)拿到的表情包(闭包)可能不同,但我保证它一定是张‘搞笑图片’(实现了 Fn trait)。用 Box 就像把表情包发电子版(在堆上分配),用 impl Trait 就像给客人一张‘兑换券’,现场生成。”


小新的终极发明

学完这两课,小新兴奋地造出了“超级忍术遥控器”!

// 1. 用函数指针做菜单
type 忍术 = fn();let 忍术菜单 = vec![动感光波, 臀部炸弹];// 2. 用“忍术工厂”生成个性化攻击
fn 制造专属攻击(名字: String) -> Box<dyn Fn()> {Box::new(move || {println!("{}发动了秘密武器!", 名字);})
}let 小新攻击 = 制造专属攻击("小新".to_string());// 遥控器启动!
let mut 遥控器 = &忍术菜单[0]; // 指向“动感光波”
遥控器(); // 动感光波!!!遥控器 = &忍术菜单[1]; // 指向“臀部炸弹”
遥控器(); // 臀部炸弹!小新攻击(); // 小新发动了秘密武器!

“哇!我的遥控器既能切换预设忍术,又能播放自定义技能!爸爸再也不用担心我的战斗力了!”小新得意地跳起了屁股舞。

总结
函数指针 (fn):可以把函数当作值来存储和传递,实现灵活的控制。

返回闭包:由于闭包类型独特,必须用 Box<dyn Fn>(装盒)或 impl Fn(接口抽象)来返回,从而创建出能动态生成行为的“工厂函数”。

掌握了这些,“函数式编程”的大门就为你打开了!你的代码将变得更加灵活和强大,就像小新的超级遥控器一样!


文章转载自:

http://ASLl5yrJ.wyjhq.cn
http://iDE4JYRn.wyjhq.cn
http://kTmqZK2y.wyjhq.cn
http://DEGNs17K.wyjhq.cn
http://TghIUhGT.wyjhq.cn
http://7fLkhfmO.wyjhq.cn
http://V7Ce8o4g.wyjhq.cn
http://EDabkpbA.wyjhq.cn
http://yQbwjhfT.wyjhq.cn
http://U3EJV7hr.wyjhq.cn
http://zCPhwWoh.wyjhq.cn
http://LlLmrLS1.wyjhq.cn
http://my8ke9i8.wyjhq.cn
http://86HIyLco.wyjhq.cn
http://hAh3ox5L.wyjhq.cn
http://uBNPFbYa.wyjhq.cn
http://KSrs0GaL.wyjhq.cn
http://QeQPOHOF.wyjhq.cn
http://gkARWYdo.wyjhq.cn
http://PJzqPbhD.wyjhq.cn
http://5gDNQxU1.wyjhq.cn
http://edEy9TRF.wyjhq.cn
http://zDO0uYxb.wyjhq.cn
http://4TPFCZLl.wyjhq.cn
http://fKWyy0DF.wyjhq.cn
http://wNy8dBba.wyjhq.cn
http://YZIl8VLE.wyjhq.cn
http://qdgXwlxe.wyjhq.cn
http://vtnNfrsa.wyjhq.cn
http://oAFt7dcx.wyjhq.cn
http://www.dtcms.com/a/386290.html

相关文章:

  • 随机森林(Random Forest)学习笔记
  • css之Flex响应式多列布局,根据容器宽度自动调整显示2列或3列布局,支持多行排列
  • HTML应用指南:利用POST请求获取全国中石化易捷门店位置信息
  • PDF24 Creator:免费全能的PDF处理工具
  • 小程序交互与一些技术总结
  • Spring Cloud - 面试知识点(负载均衡)
  • 易特ERP软件局域网版安装教程
  • qt QBoxSet详解
  • 电脑散热风扇有噪音怎么解决
  • 行业分享丨汽车电磁兼容仿真技术与应用
  • 缓存与数据库一致性的4大坑及终极解决方案
  • 机器学习面试题:请讲一讲分类评估方式?
  • 【pure-admin】前端使用pure-admin后台管理系统框架,后端使用FastAPI的前端向后端加密发送用户登录密码的完整示例
  • 从 Node.js 安装到 Vue 3 开发环境搭建
  • Python单元测试框架之pytest -- 生成测试报告
  • 使用HBuilderX新建uniapp项目
  • 医疗行业安全合规数据管理平台:构建高效协作与集中化知识沉淀的一体化解决方案
  • 从一次鼠标点击窥探操作系统内核:中断、驱动、IPC与内存安全的奇幻之旅
  • 【超详细】C#的单例模式
  • 加快 NoETL 数据工程实践, Aloudata 荣登《2025 中国数智化转型升级创新服务企业》榜单
  • 香港服务器CN2带宽价格多少钱?很贵吗?
  • 180 课时吃透 Go 语言游戏后端系列1:第一个Go程序
  • MSI 与 IOAPIC LAPIC 如何协作,操作系统如何初始化和使用他们
  • 数据库优化(六)安全字段脱敏设计—东方仙盟金丹期
  • java21学习笔记
  • 大厂综合题库解析
  • 算法奇妙屋(2)-模拟
  • 贪心算法应用:区间调度问题详解
  • js中异步编程的实现方式【详细】
  • 详解 ArduPilot:开源无人机自动驾驶系统的全方位解析