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

学习笔记十九——Rust多态

🧩 Rust 多态终极通俗指南

📚 目录导航

  1. 多态一句话概念
  2. 静态分派 vs 动态分派——根本差异
  3. 参数化多态(泛型)
    3.1 函数里的泛型
    3.2 结构体里的泛型
    3.3 方法里的泛型
    3.4 枚举里的泛型
  4. Ad hoc 多态(特例多态)
  5. 子类型多态(dyn Trait 动态分派)
  6. 何时选哪种?极简速查 + 完整运行示例
  7. 高级技巧 & 常见坑
  8. 一句口诀快速回忆

1️⃣ 多态一句话概念

多态(Polymorphism)= “同一个调用,让不同类型各做各的事”——调用方不用关心实现细节。
现实类比:对不同门说“开门”,车门、房门、电梯门会各自打开,但指令只用写一次。


2️⃣ 静态分派 vs 动态分派——根本差异

维度静态分派动态分派
关键字<T> 泛型、普通 trait 约束dyn Trait&dyn / Box<dyn> …)
决定时机编译期运行期
编译器动作单态化:为每种具体类型复制/生成专属机器码生成 vtable(虚函数表,保存方法指针)
运行成本每次方法调用多一次 vtable 查表 + 间接跳转
代表场景性能敏感、类型已知插件系统、异构集合、运行期才能确定类型

3️⃣ 参数化多态(泛型)

用占位符 <T> 写一次代码 → 编译期复制多份, 运行开销。

3.1 函数里的泛型

// <T: Copy + Mul<Output=T>> —— T 要能 Copy 且能相乘
fn square<T: Copy + std::ops::Mul<Output = T>>(x: T) -> T {x * x
}fn main() {println!("{}", square(3));    // i32println!("{}", square(2.5));  // f64
}

运行输出

9
6.25

3.2 结构体里的泛型

#[derive(Debug)]
struct Point<T> { x: T, y: T }fn main() {let int_pt = Point { x: 1,   y: 2   };   // Point<i32>let f_pt   = Point { x: 1.0, y: 2.0 };   // Point<f64>println!("{:?}\n{:?}", int_pt, f_pt);
}

输出

Point { x: 1, y: 2 }
Point { x: 1.0, y: 2.0 }

3.3 方法里的泛型

#[derive(Debug)]
struct Point<T> { x: T, y: T }impl<T> Point<T> {// 方法再引入新的 Ufn mixup<U>(self, other: Point<U>) -> Point<U> {Point { x: other.x, y: other.y }}
}fn main() {let p1 = Point { x: 5, y: 10 };let p2 = Point { x: "左", y: "右" };let p3 = p1.mixup(p2);println!("{:?}", p3);
}

输出

Point { x: "左", y: "右" }

3.4 枚举里的泛型

#[derive(Debug)]
enum MyResult<T, E> {Ok(T),Err(E),
}fn main() {let ok    : MyResult<u32, &str> = MyResult::Ok(200);let err   : MyResult<u32, &str> = MyResult::Err("网络错误");println!("{:?}\n{:?}", ok, err);
}

输出

Ok(200)
Err("网络错误")

4️⃣ Ad hoc 多态(特例多态)

Ad hoc 来自拉丁语 ad hoc,意为“为此而生”“临时特制”。
在代码中就是:不同类型为同一接口各写一套实现

use std::fmt::Display;trait Say { fn say(&self); }                // 公共接口impl Say for String {                       // 为 String 定制fn say(&self) { println!("📢 字符串:{}", self); }
}impl Say for i32 {                          // 为 i32 定制fn say(&self) { println!("🔢 数字:{}", self); }
}fn shout<T: Say + Display>(x: T) {          // 静态分派,无 vtablex.say();println!("(Display 再打印一次:{})", x);
}fn main() {shout("Hello".to_string());shout(42);
}

输出

📢 字符串:Hello
(Display 再打印一次:Hello)
🔢 数字:42
(Display 再打印一次:42)

5️⃣ 子类型多态(dyn Trait 动态分派)

5.1 关键词拆解

名词通俗解释
dyndynamic,告诉编译器“运行期再决定真实类型”
Trait 对象胖指针 (数据指针, vtable 指针)
vtable虚函数表:方法名 → 函数地址

5.2 内存示意图

Box<dyn Shape> (16 字节)
┌────────────┬────────────┐
│ data_ptr   │ vtable_ptr │
└────────────┴────────────┘
data_ptr  → 具体对象 (Circle / Square)
vtable_ptr→ [draw: fn, area: fn, ...]

5.3 最小示例

trait Draw { fn draw(&self); }              // 统一接口struct Button { label: String }
struct Label  { text: String }impl Draw for Button {fn draw(&self) { println!("🔘 按钮:{}", self.label); }
}
impl Draw for Label  {fn draw(&self) { println!("🏷️ 标签:{}", self.text); }
}fn render(ui: &[Box<dyn Draw>]) {           // 接受异构集合for w in ui { w.draw(); }               // 运行期查 vtable
}fn main() {let ui: Vec<Box<dyn Draw>> = vec![Box::new(Button { label: "确定".into() }),Box::new(Label  { text: "版本 1.0".into() }),];render(&ui);
}

输出

🔘 按钮:确定
🏷️ 标签:版本 1.0

6️⃣ 何时选哪种?极简速查 + 完整运行示例

场景首选方案为什么
性能极限、类型已知泛型(参数化多态)单态化 ➜ 零成本
给现有类型统一接口Ad hoc 多态各类型各写实现,仍静态分派
一个集合装不同类型Box<dyn Trait>运行期决定类型
隐藏返回值细节且想静态分派-> impl TraitAPI 只露能力,内部零开销

6.1 Box<dyn Trait> & impl Trait 对比示例

trait Animal { fn sound(&self) -> &'static str; }// --------------------------- 动态分派 ---------------------------
struct Dog; struct Cat;
impl Animal for Dog { fn sound(&self) -> &'static str { "汪" } }
impl Animal for Cat { fn sound(&self) -> &'static str { "喵" } }fn zoo() {                                   // 一个笼子装不同动物let list: Vec<Box<dyn Animal>> = vec![Box::new(Dog), Box::new(Cat)];for a in &list { println!("{}", a.sound()); }   // vtable 调度
}// --------------------------- 隐藏返回类型 -------------------------
fn odds() -> impl Iterator<Item = i32> {(0..6).filter(|x| x % 2 == 1)             // 返回类型被隐藏
}fn main() {zoo();                                    // 动态分派示例for n in odds() { print!("{} ", n); }     // impl Trait 示例
}

输出

汪
喵
1 3 5 

7️⃣ 高级技巧 & 常见坑

技巧 / 坑说明
Blanket Implimpl<T: Display> ToString for T 一行给所有可 Display 的类型自动实现 to_string()
对象安全规则只有“对象安全”的 Trait 才能用 dyn Trait:① 不能有泛型方法;② 方法签名里不能直接用 Self 作为参数或返回值(除放在关联类型里)
性能误区动态分派的间接跳转成本很小,除非在紧密内层循环,否则无需过早优化

8️⃣ 一句口诀快速回忆

“能静不动,要扩用 Ad‑hoc;类型未知,用 dyn 出锅。”

  • 参数化多态 <T> → 静态分派,零成本
  • Ad hoc 多态 trait + impl → 静态分派,专属实现
  • 子类型多态 dyn Trait → 动态分派,vtable 调度
  • 隐藏返回类型 -> impl Trait → 静态分派 + 封装

相关文章:

学习笔记十九——Rust多态

&#x1f9e9; Rust 多态终极通俗指南 &#x1f4da; 目录导航 多态一句话概念静态分派 vs 动态分派——根本差异参数化多态&#xff08;泛型&#xff09; 3.1 函数里的泛型 3.2 结构体里的泛型 3.3 方法里的泛型 3.4 枚举里的泛型Ad hoc 多态&#xff08;特例多态&#xff0…...

交换机与路由器的主要区别:深入分析其工作原理与应用场景

在现代网络架构中&#xff0c;交换机和路由器是两种至关重要的设备。它们在网络中扮演着不同的角色&#xff0c;但很多人对它们的工作原理和功能特性并不十分清楚。本文将深入分析交换机与路由器的主要区别&#xff0c;并探讨它们的工作原理和应用场景。 一、基本定义 1. 交换…...

【Oracle专栏】Oracle中的虚拟列

Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.背景 在EXP方式导出时&#xff0c;发现 出现如下提示 EXP-00107: virtual column 不支持&#xff0c;因此采用expdp方式导出。于是本文针对oracle虚拟列进行简单介绍。 2. 相…...

2020 年 7 月大学英语四级考试真题(组合卷)——解析版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;目前中南大学MBA在读&#xff0c;也考取过HCIE Cloud Computing、CCIE Security、PMP、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &…...

大语言模型的训练、微调及压缩技术

The rock can talk — not interesting. The rock can read — that’s interesting. &#xff08;石头能说话&#xff0c;不稀奇。稀奇的是石头能读懂。&#xff09; ----硅谷知名创业孵化器 YC 的总裁 Gar Tan 目录 1. 什么是大语言模型&#xff1f; 2. 语言建模&#xff…...

NEAT 算法解决 Lunar Lander 问题:从理论到实践

NEAT 算法解决 Lunar Lander 问题:从理论到实践 0. 前言1. 定义环境2. 配置 NEAT3. 解决 Lunar lander 问题小结系列链接0. 前言 在使用 NEAT 解决强化学习问题一节所用的方法只适用于较简单的强化学习 (reinforcement learning, RL) 环境。在更复杂的环境中使用同样的进化解…...

firewall指令

大家好,今天我们继续来了解服务管理,来看看打开或关闭指定端口,那么话不多说,开始吧. 1.打开或者关闭指定端口 在真正的生产环境,往往需要防火墙,但问题来了,如果我们把防火墙打开,那么外部请求数据包就不能跟服务器监听通讯,这时,需要打开指定的端口,比如80,22,8080等. 2.fi…...

【MySQL】MySQL表的增删改查(CRUD) —— 上篇

目录 MySQL表的增删改查&#xff08;CRUD&#xff09; 1. 新增&#xff08;Create&#xff09;/插入数据 1.1 单行数据 全列插入 insert into 表名 values(值, 值......); 1.2 单行数据 指定列插入 1.3 多行数据 指定列插入 1.4 关于时间日期&#xff08;datetime&am…...

STM32的三种启动方式

目录 一、从主闪存存储器启动&#xff08;Main Flash Memory&#xff09; 二、从系统存储器启动&#xff08;System Memory&#xff09; 三、从内置SRAM启动&#xff08;Embedded SRAM&#xff09; 一、从主闪存存储器启动&#xff08;Main Flash Memory&#xff09; >&g…...

软考高级系统架构设计师-第15章 知识产权与标准化

【本章学习建议】 根据考试大纲&#xff0c;本章主要考查系统架构设计师单选题&#xff0c;预计考3分左右&#xff0c;较为简单。 15.1 标准化基础知识 1. 标准的分类 分类 内容 国际标准&#xff08;IS&#xff09; 国际标准化组织&#xff08;ISO&#xff09;、国际电工…...

Spring Boot 整合 DeepSeek 实现AI对话 (保姆及教程)

文章目录 文章目录 前言 一、创建 spring boot 工程 二、申请key 三、修改配置文件 application.properties 四、编写控制器&#xff08;controller&#xff09; 五、运行调试 前言 提示&#xff1a;随着人工智能的不断发展&#xff0c;ai这门技术也越来越重要&#xff0c;很多…...

Java File 类详解

Java File 类详解 File 类是 Java 中用于表示文件和目录路径名的抽象类&#xff0c;位于 java.io 包中。它提供了丰富的 API&#xff0c;用于操作文件系统&#xff0c;包括创建、删除、重命名、查询文件属性等功能。 1. File 类核心知识点 &#xff08;1&#xff09;构造方法…...

通过特定协议拉起 electron 应用

在 Android 通过 sheme 协议可以拉起其他应用。 electron 应用也可以通过类似特定协议被拉起。 在同时有 web、客户端的应用里&#xff0c;可以通过这种方式在 web 拉起客户端。 支持拉起客户端 const PROTOCOL xxxif (process.defaultApp) {// 这里是开发环境&#xff0c;有…...

前端与传统接口的桥梁:JSONP解决方案

1.JSONP原理 1.1.动态脚本注入 说明&#xff1a;通过创建 <script> 标签绕过浏览器同源策略 1.2.回调约定 说明&#xff1a;服务端返回 函数名(JSON数据) 格式的JS代码 1.3.自动执行 说明&#xff1a;浏览器加载脚本后立即触发前端预定义的回调函数&#xff08;现代开…...

Vue3中provide和inject数据修改规则

在 Vue3 中&#xff0c;通过 inject 接收到的数据是否可以直接修改&#xff0c;取决于 provide 提供的值的类型和响应式处理方式&#xff1a; 1. 若提供的是普通值&#xff08;非响应式数据&#xff09; javascript 复制 // 父组件 provide(staticValue, 123); 子组件修改行…...

Mac-VScode-C++环境配置

mac上自带了clang所以不是必须下载Homebrew 下面是配置文件&#xff08;注释记得删一下&#xff09; package.json {"name": "git-base","displayName": "%displayName%","description": "%description%",&quo…...

Linux 文件系统目录结构详解

Linux 文件系统目录结构详解 Linux 文件系统遵循 Filesystem Hierarchy Standard (FHS) 标准&#xff0c;定义了各个目录的用途和文件存放规则。无论是开发者、运维工程师还是普通用户&#xff0c;理解这些目录的作用都至关重要。本文将全面解析 Linux 的目录结构&#xff0c;…...

编码器---正交编码器

一、正交编码器定义与核心作用 正交编码器&#xff08;Orthogonal Encoder&#xff09;&#xff0c;又称增量式编码器&#xff0c;是一种通过输出两路相位差90的脉冲信号&#xff08;A相、B相&#xff09;来测量旋转角度、速度和方向的传感器。其核心优势是通过A/B相的脉冲顺序…...

Java Streams 使用教程

简介 Stream 是 Java 8 引入的一个 函数式编程特性&#xff0c;可以让我们用声明式的方式操作集合&#xff08;如 List、Set、Map 等&#xff09;。 核心作用是&#xff1a; 从集合中提取数据&#xff08;流&#xff09; 对数据做中间操作&#xff08;filter/map/sort...&am…...

1001: 自由落体的计算

题目描述 一球从m米高度自由下落&#xff0c;每次落地后返回原高度的一半&#xff0c;再落下。 求它在第n次触地时会反弹多高&#xff1f;直到第n次触地时共经过多少米&#xff1f; 输入 一行,包含两个数m, n 其中0 < m < 1,000,000,000 0 < n < 1,000,000,000 输…...

开发环境解决浏览器层面跨域问题

适用于开发环境临时调试等情况 新建一个 Chrome 的快捷方式&#xff0c;目标后面跟上&#xff1a; –disable-web-security --disable-gpu --user-data-dir%LOCALAPPDATA%\Google\chromeTemp 打开后会给出不安全的提示...

2025年渗透测试面试题总结-拷打题库07(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 2025年渗透测试面试题总结-拷打题库07 1. CMS目录扫描的意义 2. 常见网站服务器容器 3. MySQL写入We…...

【leetcode刷题日记】lc.300-最长递增子序列

目录 1.题目 2.代码 1.题目 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,…...

游戏引擎学习第236天:GPU 概念概述

回顾并展望通过视频采集卡进行流媒体传输的未来 昨天&#xff0c;我们迈出了大胆的一步&#xff0c;决定初始化硬件的 3D 加速&#xff0c;因为我有点厌倦了我们的游戏没有垂直同步&#xff08;vsync&#xff09;。如今&#xff0c;在 Windows 上&#xff0c;我找不到一种可靠…...

深入理解Linux中的线程控制:多线程编程的实战技巧

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; POSIX线程&#xff08;Pthreads&#xff09; 是一种在 POSIX 标准下定义的线程库&#xff0c;它为多线程编程提供了统一的接口&#xff0c;主要用于 UNIX 和类 UNIX 系统&#xff08;如 Linux、MacOS 和 BS…...

【题解-Acwing】790. 数的三次方根

题目:790. 数的三次方根 题目描述 给定一个浮点数 n,求它的三次方根。 输入 共一行,包含一个浮点数 n 。 输出 共一行,包含一个浮点数,表示问题的解。 注意,结果保留 6 位小数。 数据范围 −10000 ≤ n ≤ 10000 时空限制 1s / 64MB 输入样例 1000.00输出样…...

【条形码识别改名工具】如何批量识别图片条形码,并以条码内容批量重命名,基于WPF和Zxing的开发总结

批量图片条形码识别与重命名系统 (WPF + ZXing)开发总结 项目适用场景 ​​电商商品管理​​:批量处理商品图片,根据条形码自动分类归档​​图书馆系统​​:扫描图书条形码快速建立电子档案​​医疗档案管理​​:通过药品条形码整理医疗图片资料​​仓储管理​​:自动化识…...

大模型微服务架构模块实现方案,基于LLaMA Factory和Nebius Cloud实现模型精调的标准流程及代码

以下是基于LLaMA Factory和Nebius Cloud实现模型精调的标准流程及代码示例&#xff0c;结合最新技术动态和行业实践整理&#xff1a; 一、LLaMA Factory本地部署方案 1. 环境配置 # 创建Python环境并安装依赖 conda create -n llama_factory python3.10 conda activate llam…...

【C++】 —— 笔试刷题day_22

一、添加字符 题目解析 这道题&#xff0c;给定两个字符串A和B&#xff0c;字符串A的长度要小于B的长度&#xff1b; 现在我们要对A字符串添加字符&#xff0c;使得A字符串长度等于B字符串的长度&#xff0c;并且要求对应位置的字母尽量相等&#xff0c;然后求出来不相等的字符…...

深入浅出:LDAP 协议全面解析

在网络安全和系统管理的世界中&#xff0c;LDAP&#xff08;轻量级目录访问协议&#xff0c;Lightweight Directory Access Protocol&#xff09;是一个不可忽视的核心技术。它广泛应用于身份管理、认证授权以及目录服务&#xff0c;尤其在企业级环境中占据重要地位。本文将从基…...