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

Rust Trait对象与多态:实现灵活的代码复用

Rust Trait对象与多态实现灵活的代码复用引言大家好我是一名正在从Rust转向Python的后端开发者。在学习Rust的过程中Trait系统是我觉得最强大的特性之一。与Python的鸭子类型不同Rust的Trait提供了一种类型安全的多态实现方式。今天我想和大家分享一下我对Rust Trait对象和多态的理解。Trait基础什么是TraitTrait是Rust中定义共享行为的方式。它类似于其他语言中的接口Interface定义了一组方法签名类型可以实现这些方法。trait Animal { fn speak(self); fn eat(self) { println!(正在吃东西); } } struct Dog; struct Cat; impl Animal for Dog { fn speak(self) { println!(汪汪!); } } impl Animal for Cat { fn speak(self) { println!(喵喵!); } fn eat(self) { println!(猫正在吃鱼); } } fn main() { let dog Dog; let cat Cat; dog.speak(); // 汪汪! dog.eat(); // 正在吃东西 cat.speak(); // 喵喵! cat.eat(); // 猫正在吃鱼 }Trait作为参数fn make_animal_speak(animal: impl Animal) { animal.speak(); } fn main() { let dog Dog; let cat Cat; make_animal_speak(dog); // 汪汪! make_animal_speak(cat); // 喵喵! }Trait对象什么是Trait对象Trait对象是一种允许我们在运行时处理不同类型的方式只要它们实现了特定的Trait。trait Draw { fn draw(self); } struct Circle { radius: f64, } struct Rectangle { width: f64, height: f64, } impl Draw for Circle { fn draw(self) { println!(画一个半径为{}的圆, self.radius); } } impl Draw for Rectangle { fn draw(self) { println!(画一个{}x{}的矩形, self.width, self.height); } } fn main() { let shapes: VecBoxdyn Draw vec![ Box::new(Circle { radius: 5.0 }), Box::new(Rectangle { width: 3.0, height: 4.0 }), ]; for shape in shapes { shape.draw(); } }Trait对象的动态分发fn draw_multiple(shapes: [Boxdyn Draw]) { for shape in shapes { shape.draw(); } } fn main() { let circle Circle { radius: 5.0 }; let rectangle Rectangle { width: 3.0, height: 4.0 }; let shapes vec![ Box::new(circle), Box::new(rectangle), ]; draw_multiple(shapes); }多态的实现使用Trait对象实现多态trait Shape { fn area(self) - f64; fn perimeter(self) - f64; } struct Square { side: f64, } struct Triangle { a: f64, b: f64, c: f64, } impl Shape for Square { fn area(self) - f64 { self.side * self.side } fn perimeter(self) - f64 { self.side * 4.0 } } impl Shape for Triangle { fn area(self) - f64 { let s (self.a self.b self.c) / 2.0; (s * (s - self.a) * (s - self.b) * (s - self.c)).sqrt() } fn perimeter(self) - f64 { self.a self.b self.c } } fn print_shape_info(shape: dyn Shape) { println!(面积: {}, shape.area()); println!(周长: {}, shape.perimeter()); } fn main() { let square Square { side: 5.0 }; let triangle Triangle { a: 3.0, b: 4.0, c: 5.0 }; print_shape_info(square); print_shape_info(triangle); }泛型与Trait对象的对比// 泛型版本静态分发 fn process_shape_genericT: Shape(shape: T) { println!(面积: {}, shape.area()); } // Trait对象版本动态分发 fn process_shape_dynamic(shape: dyn Shape) { println!(面积: {}, shape.area()); } fn main() { let square Square { side: 5.0 }; process_shape_generic(square); let triangle Triangle { a: 3.0, b: 4.0, c: 5.0 }; process_shape_dynamic(triangle); }Trait对象的约束Sized约束trait MyTrait { fn do_something(self); } struct MyStruct; impl MyTrait for MyStruct { fn do_something(self) { println!(做某事); } } // 使用?Sized允许Trait对象 fn use_trait_objectT: MyTrait ?Sized(t: T) { t.do_something(); } fn main() { let obj: Boxdyn MyTrait Box::new(MyStruct); use_trait_object(*obj); }static生命周期trait Logger { fn log(self, message: str); } struct ConsoleLogger; impl Logger for ConsoleLogger { fn log(self, message: str) { println!(日志: {}, message); } } fn create_logger() - Boxdyn Logger static { Box::new(ConsoleLogger) } fn main() { let logger create_logger(); logger.log(Hello World); }实际应用场景场景1日志系统trait Logger { fn log(self, level: str, message: str); } struct ConsoleLogger; struct FileLogger { filename: String, } impl Logger for ConsoleLogger { fn log(self, level: str, message: str) { println!([{}] {}, level, message); } } impl Logger for FileLogger { fn log(self, level: str, message: str) { println!(写入文件 {}: [{}] {}, self.filename, level, message); } } struct App { logger: Boxdyn Logger, } impl App { fn new(logger: Boxdyn Logger) - Self { App { logger } } fn run(self) { self.logger.log(INFO, 应用启动); self.logger.log(DEBUG, 正在处理请求); self.logger.log(ERROR, 发生错误); } } fn main() { let console_logger Box::new(ConsoleLogger); let app App::new(console_logger); app.run(); }场景2插件系统trait Plugin { fn name(self) - str; fn initialize(mut self); fn execute(self, input: str) - String; } struct HelloPlugin; struct ReversePlugin; impl Plugin for HelloPlugin { fn name(self) - str { hello } fn initialize(mut self) { println!(初始化Hello插件); } fn execute(self, input: str) - String { format!(Hello, {}!, input) } } impl Plugin for ReversePlugin { fn name(self) - str { reverse } fn initialize(mut self) { println!(初始化Reverse插件); } fn execute(self, input: str) - String { input.chars().rev().collect() } } struct PluginManager { plugins: VecBoxdyn Plugin, } impl PluginManager { fn new() - Self { PluginManager { plugins: Vec::new() } } fn add_plugin(mut self, plugin: Boxdyn Plugin) { self.plugins.push(plugin); } fn initialize_all(mut self) { for plugin in mut self.plugins { plugin.initialize(); } } fn execute_plugin(self, name: str, input: str) - OptionString { for plugin in self.plugins { if plugin.name() name { return Some(plugin.execute(input)); } } None } } fn main() { let mut manager PluginManager::new(); manager.add_plugin(Box::new(HelloPlugin)); manager.add_plugin(Box::new(ReversePlugin)); manager.initialize_all(); if let Some(result) manager.execute_plugin(hello, World) { println!({}, result); // Hello, World! } if let Some(result) manager.execute_plugin(reverse, Hello) { println!({}, result); // olleH } }Trait对象的性能考虑虚函数表// Trait对象包含一个数据指针和一个虚函数表指针 // 虚函数表存储了实现的方法地址 trait MyTrait { fn method1(self); fn method2(self); } struct MyStruct; impl MyTrait for MyStruct { fn method1(self) { println!(method1); } fn method2(self) { println!(method2); } } fn main() { let obj: Boxdyn MyTrait Box::new(MyStruct); // obj包含: // 1. 指向MyStruct数据的指针 // 2. 指向虚函数表的指针 obj.method1(); }静态分发 vs 动态分发// 静态分发编译时确定调用哪个方法 fn static_dispatchT: MyTrait(obj: T) { obj.method1(); } // 动态分发运行时通过虚函数表查找方法 fn dynamic_dispatch(obj: dyn MyTrait) { obj.method1(); }实战项目图形渲染系统trait Renderable { fn render(self); fn get_bounds(self) - (i32, i32, i32, i32); } struct Circle { x: i32, y: i32, radius: i32, } struct Rectangle { x: i32, y: i32, width: i32, height: i32, } struct Text { x: i32, y: i32, content: String, } impl Renderable for Circle { fn render(self) { println!(渲染圆形: ({}, {}), 半径: {}, self.x, self.y, self.radius); } fn get_bounds(self) - (i32, i32, i32, i32) { ( self.x - self.radius, self.y - self.radius, self.x self.radius, self.y self.radius, ) } } impl Renderable for Rectangle { fn render(self) { println!(渲染矩形: ({}, {}), {}x{}, self.x, self.y, self.width, self.height); } fn get_bounds(self) - (i32, i32, i32, i32) { (self.x, self.y, self.x self.width, self.y self.height) } } impl Renderable for Text { fn render(self) { println!(渲染文本: ({}, {}), 内容: {}, self.x, self.y, self.content); } fn get_bounds(self) - (i32, i32, i32, i32) { let text_width self.content.len() * 8; let text_height 16; (self.x, self.y, self.x text_width as i32, self.y text_height) } } struct Renderer { objects: VecBoxdyn Renderable, } impl Renderer { fn new() - Self { Renderer { objects: Vec::new() } } fn add_object(mut self, obj: Boxdyn Renderable) { self.objects.push(obj); } fn render_all(self) { for obj in self.objects { obj.render(); } } fn cull_invisible(mut self, viewport: (i32, i32, i32, i32)) { self.objects.retain(|obj| { let (x1, y1, x2, y2) obj.get_bounds(); x1 viewport.2 x2 viewport.0 y1 viewport.3 y2 viewport.1 }); } } fn main() { let mut renderer Renderer::new(); renderer.add_object(Box::new(Circle { x: 100, y: 100, radius: 50 })); renderer.add_object(Box::new(Rectangle { x: 200, y: 200, width: 100, height: 50 })); renderer.add_object(Box::new(Text { x: 50, y: 50, content: Hello World.to_string() })); renderer.render_all(); renderer.cull_invisible((0, 0, 150, 150)); println!(\n裁剪后:); renderer.render_all(); }与Python多态的对比特性Rust Trait对象Python 鸭子类型类型检查编译时运行时性能动态分发有轻微开销动态查找开销安全性类型安全可能运行时错误灵活性需要显式实现自动适配总结Rust的Trait对象提供了一种类型安全的多态实现方式。通过使用Trait对象我们可以实现代码复用不同类型可以共享相同的行为提高灵活性在运行时处理不同类型保持类型安全编译时检查确保实现正确作为从Rust转向Python的开发者我发现Rust的Trait系统比Python的鸭子类型更加严格和安全。虽然灵活性稍差但类型安全带来的好处是巨大的。延伸阅读Rust官方文档 - Trait对象Rust By Example - Trait对象The Rust Programming Language - Trait Objects

相关文章:

Rust Trait对象与多态:实现灵活的代码复用

Rust Trait对象与多态:实现灵活的代码复用 引言 大家好,我是一名正在从Rust转向Python的后端开发者。在学习Rust的过程中,Trait系统是我觉得最强大的特性之一。与Python的鸭子类型不同,Rust的Trait提供了一种类型安全的多态实现…...

Code Buddy:实时监控AI编程助手状态,提升开发效率与掌控感

1. 项目概述如果你和我一样,日常开发重度依赖 Claude Code、Cursor 这类 AI 编程助手,那你肯定遇到过这个场景:你让 AI 去执行一个复杂的find或grep命令,然后切到浏览器查资料,或者去回个消息。几分钟后回来&#xff0…...

【懒人运维】rsyslog+mysql+loganalyzer 日志服务器搭建

文章目录运行环境数据库配置rsyslog配置loganalyzer安装防火墙配置《中华人民共和国网络安全法》第二十一条第三项明确规定,网络运营者必须采取监测、记录网络运行状态和网络安全事件的技术措施,并按照规定留存相关的网络日志不少于六个月‌。‌目前&…...

[Deep Agents:LangChain的Agent Harness-03]FilesystemMiddleware:赋能Agent读写文件及管理长上下文

通过“构建抽象的文件系统”我们知道,Deep Agents的文件系统是建立在一个利用BackendProtocol协议抽象的文件系统之上的,使得Agent能够以统一的方式进行文件操作,无论底层存储是本地磁盘、云端S3、数据库还是内存。这种设计不仅提供了极大的灵…...

6条Claude Code实践中的经验与思考

Claude Code系列回顾 目前在实践和应用Claude Code,顺便分享一些在实践过程中的经验,没想竟然写成一个系列了。如果你也对Claude Code感兴趣,可以先回顾一下之前的文章,然后开始今天的文章。 第1篇:《国内环境下的Cl…...

OpenPicoRTOS:ARM Cortex-M微控制器上的极简实时操作系统设计与实战

1. 项目概述:一个为微控制器而生的实时操作系统如果你在嵌入式领域摸爬滚打过几年,尤其是在资源极其受限的微控制器(MCU)上开发过复杂应用,那你一定对“实时性”和“资源占用”这对矛盾深有体会。商业RTOS(…...

从白炽灯到LED:家庭节日照明升级的技术原理、选购与实战指南

1. 从白炽灯到LED:一个拖延了三年才完成的家庭照明升级 每年一到这个时候,看着邻居家窗户上闪烁的彩灯,再看看自家车库里那几箱缠成一团、每年都要花半天时间测试维修的旧灯串,我就下定决心:今年一定要换成LED的。这个…...

基于React与Vite的现代化开源仪表盘开发实战指南

1. 项目概述:一个面向开发者的开源仪表盘解决方案最近在折腾一个内部监控系统,需要快速搭建一个数据可视化的前端界面。找了一圈现成的方案,要么太重,要么定制化程度不够,要么就是设计风格过于陈旧。直到在GitHub上发现…...

苏州沃虎电子(VOOHU)功率线用共模电感WHACM07A40R101产品介绍

苏州沃虎电子科技有限公司(品牌:VOOHU)供应的 WHACM07A40R101 是一款高性能功率线用共模电感,采用紧凑的7.06.04.0mm封装,专为电源线电磁干扰(EMI)抑制设计。该产品具备大电流承载能力和优异的共…...

面向零基础初学者,从环境搭建到发布上线,手把手教你开发第一个微信小程序(第5章-WXSS入门)

5.1 WXSS是什么? WXSS(WeiXin Style Sheets)是微信小程序的样式语言,类似于网页开发中的CSS。 WXSS vs CSS对比CSSWXSS选择器支持完整选择器支持大部分选择器单位px, em, remrpx, px布局flex, grid主要用flex最大的区别&#xff1…...

AI编码助手效率革命:ai-codex工具如何通过静态分析生成项目索引

1. 项目概述:为AI编码助手打造“即时上下文”如果你和我一样,每天都在和Claude Code、Cursor或者GitHub Copilot这类AI编码助手打交道,那你肯定也经历过这个“启动成本”的烦恼:每次开启一个新对话,助手做的第一件事就…...

30个客户,30本定制手册:文档团队的噩梦

上周,一家做大型设备的文档主管给我算了一笔账。他们有30个大客户,每个客户都要求专属手册。A客户要求LOGO换成他们的,操作界面术语用他们的内部叫法;B客户要求删除某些技术参数,只保留操作步骤;C客户要求所…...

技能迁移器:构建个人开发环境一键迁移框架的设计与实践

1. 项目概述:技能迁移器的核心价值最近在GitHub上看到一个挺有意思的项目,叫“skill-migrator”。光看名字,你可能会联想到数据迁移或者系统迁移,但它的核心其实是关于“人”的——如何将一个人的技能、知识、乃至工作习惯&#x…...

ECHO框架:语言驱动机器人控制的边缘-云协同技术

1. ECHO框架:语言驱动人形机器人控制的边缘-云协同架构在机器人控制领域,如何让机器人理解并执行自然语言指令一直是个关键挑战。传统方法要么受限于硬件计算能力,要么面临语义理解与实时控制的矛盾。ECHO框架通过创新的边缘-云协同架构&…...

【STM32】启动过程分析

本文记录一下STM32F4系列的启动过程,也就是从STM32芯片上电复位执行的第一条指令,到执行用户编写的main函数这之间的过程。1.启动模式上电复位,硬件复位和软件复位。当产生复位,并且离开复位状态后,CM4 内核做的第一件…...

OpenClaw任务控制中心:构建自动化工作流的轻量级调度平台

1. 项目概述与核心价值最近在折腾一些自动化任务时,发现很多开源工具虽然功能强大,但往往需要自己写胶水代码来串联,或者需要一个统一的界面来管理和监控。这让我想起了以前在运维和开发中经常遇到的痛点:脚本分散、日志难查、状态…...

总结“从输入URL到展示出页面“ 过程发生了什么

当我们在浏览器地址栏输入URL并按下回车后,背后会经历一系列复杂的步骤,最终将网页内容呈现在眼前,整个过程可以分为以下几个阶段:一、URL解析与处理浏览器首先会判断输入的内容是否为合法URL,如果是域名(如…...

javassit使用过程的坑

https://segmentfault.com/a/1190000044154053 https://blog.csdn.net/Kingairy/article/details/104003524 经过不断的试错和研究&#xff0c;总结如下&#xff1a; 以CtMethod#setBody 方法为例 不要在代码中使用范型&#xff0c;哪怕是定义List<Object>这样基础范型…...

L-system与硬件补偿技术在自动钢琴音乐生成中的应用

1. L-system与硬件补偿技术概述L-system&#xff08;Lindenmayer系统&#xff09;作为一种形式化语法&#xff0c;最初由生物学家Aristid Lindenmayer于1968年提出&#xff0c;用于模拟植物的生长过程。其核心机制是通过字符串重写规则生成具有自相似性的复杂结构。在音乐生成领…...

从零构建团队专属CLI工具:自动化项目脚手架与代码生成实践

1. 项目概述&#xff1a;一个命令行工具的诞生与价值最近在整理自己的工具链&#xff0c;发现一个挺有意思的现象&#xff1a;很多开发者&#xff0c;包括我自己&#xff0c;都习惯性地把一些高频、重复的脚本操作散落在各个项目的根目录下&#xff0c;或者干脆写个简陋的Makef…...

实战入口:Claude 到底在哪用?网页版、桌面端与多端场景全解

最近在 se.zzmax.cn 上直接体验 Claude 各型号&#xff0c;发现很多同学第一次想用 Claude&#xff0c;卡住的往往不是“怎么问”&#xff0c;而是“从哪儿进”。Anthropic 目前提供了多个官方入口&#xff0c;不同入口适配的使用场景、能力和 workflow 集成深度并不一样。下面…...

MCP协议赋能Ollama:本地大模型工具调用的标准化实践

1. 项目概述&#xff1a;当MCP遇上Ollama&#xff0c;本地AI工作流的“最后一公里” 如果你和我一样&#xff0c;是个喜欢折腾本地大模型的开发者&#xff0c;那你肯定对Ollama不陌生。它让在本地运行Llama、Mistral、Qwen这些开源大模型变得像 ollama run llama3.2 一样简单…...

redis 8.6.3 最新版重磅发布:安全修复、核心 Bug 修复与模块优化全面升级

2026年5月5日&#xff0c;Redis 8.6.3 正式发布。 这是一个非常值得关注的版本&#xff0c;因为官方明确标注了 Update urgency: SECURITY&#xff0c;说明本次更新包含安全修复&#xff0c;建议尽快升级。 从发布内容来看&#xff0c;8.6.3 不只是一次常规的小版本迭代&#x…...

2026-05-09:不同元素和至少为 K 的最短子数组长度。用go语言,给定一个整数数组 nums 和一个整数 k。你需要在数组中找一个连续的非空子数组,使得这个子数组里不同元素的种类数对应的取值之

2026-05-09&#xff1a;不同元素和至少为 K 的最短子数组长度。用go语言&#xff0c;给定一个整数数组 nums 和一个整数 k。你需要在数组中找一个连续的非空子数组&#xff0c;使得这个子数组里不同元素的种类数对应的取值之和&#xff08;也就是&#xff1a;每个数只算一次&am…...

【Python实战】告别杂乱脚本!基于SOLID原则与策略模式的 PDF转Word 批量处理系统

&#x1f4dd; 前言&#xff1a;为什么要造这个“轮子”&#xff1f; 在日常的学习和开发中&#xff0c;我们经常遇到需要将大量 PDF 转换为 Word 文档的场景。市面上的在线工具要么满屏广告&#xff0c;要么限制文件大小和数量&#xff1b;而网上的 Python 脚本往往是简单的“…...

告别冗余!Linux软件卸载命令全攻略,让你的系统焕然一新

还在为Linux系统软件残留烦恼吗&#xff1f;本攻略汇集APT、YUM、DNF、RPM等主流包管理器的卸载命令&#xff0c;并提供手动安装软件的清理方法。告别臃肿&#xff0c;轻松卸载&#xff0c;让你的Linux系统告别卡顿&#xff0c;运行如飞。在Linux系统中&#xff0c;卸载软件的方…...

【线性代数笔记】秩、线性相关性与等价向量组的核心逻辑总结

博主简介&#xff1a;05后理工男&#xff0c;CSDN 技术博主。目前正在攻读计算机专业&#xff0c;同步复习 408 及数学基础。 笔记说明&#xff1a;本文为线性代数关于“秩”与“向量组相关性”的学习笔记&#xff0c;重点记录了判定方法与核心定理。一、 线性表示与方程组解的…...

Cursor AI编程效率追踪器:本地化数据采集与可视化分析实践

1. 项目概述&#xff1a;一个为开发者量身定制的效率追踪器最近在GitHub上看到一个挺有意思的项目&#xff0c;叫cursor-usage-tracker。光看名字&#xff0c;你可能觉得这又是一个平平无奇的“使用情况追踪器”。但如果你是一位深度使用Cursor&#xff08;那个集成了AI能力的现…...

BarTender如何取消激活和重新激活

一、取消激活1、多台电脑、服务端取消激活方法A、打开Administration ConsoleB、许可—选中当前许可证—右键选择取消激活许可证C、点击下一步D、取消激活中E、取消激活成功&#xff0c;许可证没有处于激活的状态2、只安装了单台电脑的情况取消激活可以按照上述取消激活方式进行…...

OpenClaw三层记忆系统:为AI助手构建可检索的长期知识库

1. 项目概述如果你和我一样&#xff0c;长期与各种AI助手打交道&#xff0c;无论是编程、写作还是日常任务规划&#xff0c;最头疼的问题之一就是“记忆”。每次对话都像是一次全新的邂逅&#xff0c;助手记不住你昨天提到的项目细节&#xff0c;也忘了上周讨论过的技术方案。这…...