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

第30章 类型系统高级话题

30.1 类型状态模式(Typestate Pattern)

30.1.1 基本概念

类型状态模式使用类型系统在编译期强制状态转换规则。

usestd::marker::PhantomData;// 状态标记structLocked;structUnlocked;// 门的类型状态structDoor<State>{_state:PhantomData<State>,}implDoor<Locked>{fnnew()->Self{println!("门已锁定");Door{_state:PhantomData,}}fnunlock(self)->Door<Unlocked>{println!("门已解锁");Door{_state:PhantomData,}}}implDoor<Unlocked>{fnopen(self){println!("门已打开");}fnlock(self)->Door<Locked>{println!("门已锁定");Door{_state:PhantomData,}}}fnmain(){letdoor=Door::<Locked>::new();letdoor=door.unlock();door.open();// ❌ 编译错误:不能直接打开锁定的门// let door = Door::<Locked>::new();// door.open();}

30.1.2 实际应用:构建器模式

structUnset;structSet<T>(T);structConfigBuilder<Name,Port>{name:Name,port:Port,}implConfigBuilder<Unset,Unset>{fnnew()->Self{ConfigBuilder{name:Unset,port:Unset,}}}impl<Port>ConfigBuilder<Unset,Port>{fnname(self,name:String)->ConfigBuilder<Set<String>,Port>{ConfigBuilder{name:Set(name),port:self.port,}}}impl<Name>ConfigBuilder<Name,Unset>{fnport(self,port:u16)->ConfigBuilder<Name,Set<u16>>{ConfigBuilder{name:self.name,port:Set(port),}}}implConfigBuilder<Set<String>,Set<u16>>{fnbuild(self)->Config{Config{name:self.name.0,port:self.port.0,}}}structConfig{name:String,port:u16,}fnmain(){letconfig=ConfigBuilder::new().name("MyApp".to_string()).port(8080).build();println!("配置: {} on port {}",config.name,config.port);// ❌ 编译错误:缺少必需字段// let config = ConfigBuilder::new().build();}

30.2 幽灵数据(PhantomData)

30.2.1 基本用法

usestd::marker::PhantomData;structSlice<'a,T>{start:*constT,end:*constT,_marker:PhantomData<&'aT>,}impl<'a,T>Slice<'a,T>{fnnew(slice:&'a[T])->Self{Slice{start:slice.as_ptr(),end:unsafe{slice.as_ptr().add(slice.len())},_marker:PhantomData,}}}

30.2.2 所有权标记

usestd::marker::PhantomData;structOwned<T>{data:*mutT,_marker:PhantomData<T>,}impl<T>DropforOwned<T>{fndrop(&mutself){unsafe{std::ptr::drop_in_place(self.data);}}}

30.3 泛型关联类型(GAT)

30.3.1 基本语法

traitContainer{typeItem<'a>whereSelf:'a;fnget<'a>(&'aself,index:usize)->Option<Self::Item<'a>>;}structVecContainer<T>{data:Vec<T>,}impl<T>ContainerforVecContainer<T>{typeItem<'a>=&'aTwhereT:'a;fnget<'a>(&'aself,index:usize)->Option<Self::Item<'a>>{self.data.get(index)}}fnmain(){letcontainer=VecContainer{data:vec![1,2,3],};ifletSome(item)=container.get(1){println!("Item: {}",item);}}

30.3.2 实际应用:迭代器

traitLendingIterator{typeItem<'a>whereSelf:'a;fnnext<'a>(&'amutself)->Option<Self::Item<'a>>;}structWindowsMut<'data,T>{data:&'datamut[T],size:usize,pos:usize,}impl<'data,T>LendingIteratorforWindowsMut<'data,T>{typeItem<'a>=&'amut[T]whereSelf:'a;fnnext<'a>(&'amutself)->Option<Self::Item<'a>>{ifself.pos+self.size>self.data.len(){returnNone;}letslice=&mutself.data[self.pos..self.pos+self.size];self.pos+=1;Some(slice)}}

30.4 const 泛型

30.4.1 基本用法

structArray<T,constN:usize>{data:[T;N],}impl<T,constN:usize>Array<T,N>{fnlen(&self)->usize{N}}fnmain(){letarr=Array{data:[1,2,3,4,5],};println!("长度: {}",arr.len());}

30.4.2 编译期计算

structMatrix<T,constROWS:usize,constCOLS:usize>{data:[[T;COLS];ROWS],}impl<T,constROWS:usize,constCOLS:usize>Matrix<T,ROWS,COLS>{fndimensions(&self)->(usize,usize){(ROWS,COLS)}}impl<T:std::ops::Add<Output=T>+Copy,constN:usize>std::ops::AddforMatrix<T,N,N>{typeOutput=Self;fnadd(self,other:Self)->Self::Output{letmutresult=self;foriin0..N{forjin0..N{result.data[i][j]=result.data[i][j]+other.data[i][j];}}result}}

30.5 类型级编程

30.5.1 类型级数字

traitNat{}structZero;structSucc<N:Nat>(std::marker::PhantomData<N>);implNatforZero{}impl<N:Nat>NatforSucc<N>{}typeOne=Succ<Zero>;typeTwo=Succ<One>;typeThree=Succ<Two>;traitAdd<Rhs:Nat>:Nat{typeOutput:Nat;}impl<N:Nat>Add<Zero>forN{typeOutput=N;}impl<N:Nat,M:Nat>Add<Succ<M>>forNwhereN:Add<M>,{typeOutput=Succ<<NasAdd<M>>::Output>;}

30.5.2 类型级列表

traitTypeList{}structNil;structCons<Head,Tail:TypeList>(std::marker::PhantomData<(Head,Tail)>);implTypeListforNil{}impl<Head,Tail:TypeList>TypeListforCons<Head,Tail>{}typeList=Cons<i32,Cons<String,Cons<bool,Nil>>>;

30.6 利用类型系统编码业务规则

30.6.1 单位类型

structMeters(f64);structKilometers(f64);implMeters{fnto_kilometers(self)->Kilometers{Kilometers(self.0/1000.0)}}implKilometers{fnto_meters(self)->Meters{Meters(self.0*1000.0)}}fnmain(){letdistance=Meters(5000.0);letkm=distance.to_kilometers();// ❌ 编译错误:类型不匹配// let sum = Meters(100.0) + Kilometers(1.0);}

30.6.2 状态机

structDraft;structPublished;structArchived;structPost<State>{content:String,_state:PhantomData<State>,}implPost<Draft>{fnnew(content:String)->Self{Post{content,_state:PhantomData,}}fnpublish(self)->Post<Published>{Post{content:self.content,_state:PhantomData,}}}implPost<Published>{fnarchive(self)->Post<Archived>{Post{content:self.content,_state:PhantomData,}}}implPost<Archived>{fndelete(self){println!("文章已删除");}}fnmain(){letpost=Post::<Draft>::new("内容".to_string());letpost=post.publish();letpost=post.archive();post.delete();}

常见误区与陷阱

误区 1:过度使用类型状态

// ❌ 不好:过度复杂structState1;structState2;structState3;// ... 10 个状态// ✅ 好:适度使用enumState{State1,State2,State3,}

误区 2:忘记 PhantomData

// ❌ 不好:编译器警告未使用的类型参数structWrapper<T>{data:*constu8,}// ✅ 好:使用 PhantomDatastructWrapper<T>{data:*constu8,_marker:PhantomData<T>,}

实战练习

练习 30.1:实现类型安全的 SQL 查询构建器

参考答案

structNoWhere;structWithWhere;structQuery<W>{table:String,where_clause:Option<String>,_marker:PhantomData<W>,}implQuery<NoWhere>{fnfrom(table:&str)->Self{Query{table:table.to_string(),where_clause:None,_marker:PhantomData,}}fnwhere_clause(self,clause:&str)->Query<WithWhere>{Query{table:self.table,where_clause:Some(clause.to_string()),_marker:PhantomData,}}}implQuery<WithWhere>{fnexecute(&self)->String{format!("SELECT * FROM {} WHERE {}",self.table,self.where_clause.as_ref().unwrap())}}fnmain(){letquery=Query::from("users").where_clause("age > 18").execute();println!("{}",query);}

本章小结

  1. 类型状态模式:在编译期强制状态转换规则
  2. PhantomData:标记类型参数的所有权和生命周期
  3. GAT:泛型关联类型支持更灵活的抽象
  4. const 泛型:编译期常量作为类型参数
  5. 类型级编程:在类型层面进行计算
  6. 业务规则编码:利用类型系统防止业务逻辑错误
  7. 零成本抽象:类型系统的检查在编译期完成
http://www.jsqmd.com/news/1129030/

相关文章:

  • CISP-PTE渗透测试知识体系详解:从基础到实战的完整能力构建路径
  • C#视觉检测翻车实录:我把OK当成NG拒收,差点被产线大姐当场“祭天”
  • C#图像处理黑魔法:揭秘直方图均衡化,如何让模糊的“马赛克”秒变高清“写真”?
  • 5分钟掌握B站缓存视频转换技巧:m4s-converter完整使用指南
  • 怎样轻松实现移动端图片滑动浏览:3个实用技巧提升用户体验
  • DuMate智能体:DuMate 浏览器插件安装指南
  • 【Linux】九.进程概念--环境变量及其相关指令
  • 高效技巧怎么用 AI 做表格,搭配 AI 导出鸭一站式搞定表格生成与导出工作
  • 【Atlas】Atlas 的 Type System 是什么?它如何支撑元模型定义?
  • F3闪存检测工具:5分钟识别扩容盘欺诈的完整指南
  • luogu----P1000 超级玛丽游戏
  • 终极指南:如何用AI增强开发工作流实现3倍效率提升
  • 从弱口令挖掘到SRC奖金:实战路径与高阶技巧全解析
  • 环境准备和使用指南
  • cpp数据结构
  • PyTorch实战:构建CK+表情识别数据管道
  • 河源市万川石英发展有限公司工厂简介
  • Nintendo Switch游戏文件终极管理指南:NSC_BUILDER完全解析
  • 存储芯片千问千答第1问:Nand SCA是什么
  • 深度解析Bottles:如何在Linux上轻松运行Windows游戏和软件
  • 第 5 篇:MAC 地址——IP 管远方,MAC 管眼前
  • Claude怎么转PDF?AI导出鸭多平台办公新方案深度评测
  • C#版“福尔摩斯”:文件监听的“潜伏”与“反侦察”艺术
  • 【Linux】八.进程概念--进程的切换,上下文数据,进程的状态,进程的优先级,以及Linux内核进程的调度队列
  • AI Agent 面试题 735:Agent的用户满意度评估方法和指标设计
  • 存储芯片千问千答第2问:盲封TT wafer是什么意思?
  • FGSM 对抗攻击实战:5行代码实现 MNIST 图像分类器 90% 成功率欺骗
  • Codex技能(Skills)完整教程:打造可复用AI工作流,让Codex变成你的专属开发助手
  • P1634 禽兽的传染病
  • Irony Detection in Urdu Text: A Comparative Study Using Machine Learning Models and Large Languag...