/*
特性(trait)概念接近于 Java 中的接口(Interface),但两者不完全相同。特性与接口相同的地方在于它们都是一种行为规范,可以用于标识哪些类有哪些方法
trait Descriptive {fn describe(&self) -> String;
}
Descriptive 规定了实现者必须有是 describe(&self) -> String 方法。(必须实现所有方法)几个非常有用的标准库特性:Drop提供了当一个值退出作用域后执行代码的功能,它只有一个drop(&mut self)方法。Borrow用于创建一个数据结构时把拥有和借用的值看作等同。AsRef用于在泛型中把一个值转换为引用。Deref<Target=T>用于把&U类型的值自动转换为&T类型。Iterator用于在集合 (collection) 和惰性值生成器 (lazy value generator) 上实现迭代器。Sized用于标记运行时长度固定的类型,而不定长的切片和特性必须放在指针后面使其运行时长度已知, 比如&[T]和Box<Trait>。*///特性简单使用
fn test_1() {trait Descriptive {fn describe(&self) -> String;}struct Person {name: String,age: u8,}impl Descriptive for Person {fn describe(&self) -> String {format!("{} {}", self.name, self.age)}}
}//特性不仅可以绑定结构体方法,还可以绑定结构体关联方法
fn test_1_2() {trait Descriptive {fn describe() -> String;}struct Person {name: String,age: u8,}impl Descriptive for Person {fn describe() -> String {//format!("{} {}", self.name, self.age)String::from("1231111111111111111111")}}fn test2_1(t:impl Descriptive){println!("{}",Person::describe());}let p =Person{name: String::from("123"),age: 12,};test2_1(p);
}//默认特性
fn test_2() {//这是特性与接口的不同点:接口只能规范方法而不能定义方法,但特性可以定义方法作为默认方法,因为是"默认",//所以对象既可以重新定义方法,也可以不重新定义方法使用默认的方法trait Descriptive {fn describe(&self) -> String {String::from("[Object]")}}struct Person {name: String,age: u8,}impl Descriptive for Person {//如果想调用特性的默认接口,把下面这段代码去掉就可以了fn describe(&self) -> String {format!("{} {}", self.name, self.age)}}let cali = Person {name: String::from("Cali"),age: 24,};println!("{}", cali.describe());
}//特性做参数
fn test_3() {trait Descriptive {fn describe(&self) -> String {String::from("[Object]")}}//任何实现了 Descriptive 特性的对象都可以作为这个函数的参数,这个函数没必要了解传入对象有没有其他属性或方法,//只需要了解它一定有 Descriptive 特性规范的方法就可以了。当然,此函数内也无法使用其他的属性与方法。fn output(object: impl Descriptive) {println!("{}", object.describe());}//特性参数还可以用这种等效语法实现:fn output2<T: Descriptive>(object: T) {println!("{}", object.describe());}//这是一种风格类似泛型的语法糖,这种语法糖在有多个参数类型均是特性的情况下十分实用:fn output3<T: Descriptive>(arg1: T, arg2: T) {println!("{}", arg1.describe());println!("{}", arg2.describe());}//特性作类型表示时如果涉及多个特性,可以用 + 符号表示,例如:trait Summary {fn describe(&self) -> String {String::from("[Summary]")}}trait Display {fn describe(&self) -> String {String::from("[Display]")}}fn output4(item: impl Summary + Display) {}fn output5<T: Summary + Display>(item: T) {}struct Person {name: String,age: u8,}impl Descriptive for Person {//如果想调用特性的默认接口,把下面这段代码去掉就可以了fn describe(&self) -> String {format!("{} -- {}", self.name, self.age)}}impl Summary for Person {fn describe(&self) -> String {format!("{} -Summary- {}", self.name, self.age)}}impl Display for Person {fn describe(&self) -> String {format!("{} -Display- {}", self.name, self.age)}}/*/------------------//复杂的实现关系可以使用 where 关键字简化,例如:fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U)->i32{}//可以简化成:fn some_function<T, U>(t: T, u: U) -> i32where T: Display + Clone,U: Clone + Debug//------------------*/impl Descriptive for () {//如果想调用特性的默认接口,把下面这段代码去掉就可以了fn describe(&self) -> String {format!("6666666666666666666666")}}let p = Person {name: String::from("liujiayu"),age: 30,};output(p);//测试()实现特性output2(());let p = Person {name: String::from("liujiayu"),age: 30,};output4(p);
}//特性做参数实现取最大数
fn test_4() {// 由于需要声明 compare 函数的第二参数必须与实现该特性的类型相同,所以 Self (注意大小写)关键字就代表了当前类型(不是实例)本身。trait Comparable {fn compare(&self, object: &Self) -> i8;}fn max<T: Comparable>(array: &[T]) -> &T {let mut max_index = 0;let mut i = 1;while i < array.len() {if array[i].compare(&array[max_index]) > 0 {max_index = i;}i += 1;}&array[max_index]}impl Comparable for f64 {fn compare(&self, object: &f64) -> i8 {if &self > &object {1} else if &self == &object {0} else {-1}}}let arr = [1.0, 3.0, 5.0, 4.0, 2.0];println!("maximum of arr is {}", max(&arr));
}//特性做返回值
fn test_5() {trait Descriptive {fn describe(&self) -> String;}struct Person {name: String,age: u8,}impl Descriptive for Person {fn describe(&self) -> String {format!("{} {}", self.name, self.age)}}fn person() -> impl Descriptive {Person {name: String::from("Cali"),age: 24,}}//但是有一点,特性做返回值只接受实现了该特性的对象做返回值且在同一个函数中所有可能的返回值类//型必须完全一样。比如结构体 A 与结构体 B 都实现了特性 Trait,下面这个函数就是错误的:struct A {}struct B {}impl Descriptive for A {fn describe(&self) -> String {String::from("A")}}impl Descriptive for B {fn describe(&self) -> String {String::from("B")}}// 编译不过// fn some_function(bl:bool) -> impl Descriptive {//      if bl {//          return A {};//      } else {//          return B {};//      }// }//some_function(false);
}//有条件实现方法
fn test_6() {//impl 功能十分强大,我们可以用它实现类的方法。但对于泛型类来说,有时我们需要区分一下它所属的泛型已经实现的方法来决定它接下来该实现的方法//这段代码声明了 A<T> 类型必须在 T 已经实现 B 和 C 特性的前提下才能有效实现此 impl 块。//(编译不过,有机会再研究)// struct A<T> {}// impl<T: B + C> A<T> {//     fn d(&self) {}// }
}//trait中可以继承.继承的意义是什么,这个例子没有体现??????
fn test_7() {println!("---------------test_7--------------");trait PrintInfo {/// 方法/函数,没有具体实现fn info(&self) {println!("base function---default");}}// InheritTrait这个trait,继承PrintInfotrait InheritTrait: PrintInfo {fn out_info(&self) {println!("inherit function---default");}}#[derive(Debug)]struct People {id: u32,            //idname: &'static str, //姓名 字符串sex: &'static str,  //性别}impl PrintInfo for People {fn info(&self) {println!("base function---Nodefault")}}impl InheritTrait for People {fn out_info(&self) {println!("inherit function---Nodefault");}}let p = People {id: 1,name: "tom",sex: "man",};p.info();p.out_info();
}//关联类型
fn test_8() {println!("---------test_8-------");/*定义:关联类型(associated types)是一个将类型占位符与 trait 相关联的方式,这样trait的方法签名中就可以使用这些占位符类型。trait的实现者会针对特定的实现在这个类型的位置指定相应的具体类型。如此可以定义一个使用多种类型的trait,直到实现此trait时都无需知道这些类型具体是什么。我们阅读Rust程序的时候,有时候会出现如下的代码:trait Iterator {type Item;fn next(&mut self) -> Option<Self::Item>;}解释:Iterator trait 有一个关联类型Item。Item是一个占位类型,同时next方法会返回Option<Self::Item>类型的值。重点:"这个trait的实现者会指定Item的具体类型。"自己的理解:这就是一个迭代器,具体遍历的是啥暂时不写死,有可能是整数类型,也有可能是字符串类型*/pub trait Tt {}impl Tt for i32 { }impl Tt for String { }/*type Item : Tt;Tt是Item的约束,必须是trait类型,代表的意思是指定Item类型A的时候,A必须实现了Tt才行*/pub trait Watch {type Item : Tt;fn inner(&self) -> Option<Self::Item>;}struct A {data: i32,}impl Watch for A {type Item = i32;fn inner(&self) -> Option<Self::Item> {Some(self.data)}}struct B {data: String,}impl Watch for B {type Item = String;fn inner(&self) -> Option<Self::Item> {Some(self.data.clone())}}let a = A{data: 10};let b = B{data: String::from("B")};assert_eq!(Some(10), a.inner());assert_eq!(Some(String::from("B")), b.inner());
}//trait继承的意义:子trait可以使用父trait的关联类型
fn test_9() {println!("---------test_9-------");trait tt1 {type AccountID;}struct Empty{}impl tt1 for Empty {type AccountID = u64;}// InheritTrait这个trait,继承PrintInfotrait tt11:tt1 {fn out_info(&self);}impl tt11 for Empty {fn out_info(&self) {println!("inherit function---default");let id:Self::AccountID = 1001;//注意带上Self:: 进行访问}}
}//trait继承的意义:子trait可以使用父trait的关联函数
fn test_9_2() {println!("---------test_9_2-------");trait TraitA {fn test_fn_traita();fn test_fn_traita_self(&self);}trait TraitA2 {fn test_fn_traita2();}trait TraitB: TraitA {fn test_fn_traitb();fn test_fn_traitb_self(&self);}trait TraitC: TraitB {fn test_fn_traitc();fn test_fn_traitc_self(&self);}struct StEmpty {}impl TraitA for StEmpty {fn test_fn_traita() {println!("fn :test_fn_traita, trait : TraitA, struct :StEmpty");}fn test_fn_traita_self(&self) {println!("fn :test_fn_traita_self, trait : TraitA, struct :StEmpty");}}impl TraitB for StEmpty {fn test_fn_traitb() {println!("fn :test_fn_traitb, trait : TraitB, struct :StEmpty");Self::test_fn_traita();}fn test_fn_traitb_self(&self) {println!("fn :test_fn_traitb_self, trait : TraitB, struct :StEmpty");//也可以调用带self的self.test_fn_traita_self();}}let t = StEmpty{};t.test_fn_traitb_self();impl TraitC for StEmpty {fn test_fn_traitc() {println!("fn :test_fn_traitc, trait : TraitC, struct :StEmpty");Self::test_fn_traita(); //实验证明可以调用他爷爷的接口}fn test_fn_traitc_self(&self) {}}// 多重继承trait TraitD: TraitA2 + TraitC {fn test_fn_traitd();}impl TraitA2 for StEmpty {fn test_fn_traita2() {println!("fn :test_fn_traita2, trait : TraitA2, struct :StEmpty");}}impl TraitD for StEmpty {fn test_fn_traitd() {println!("fn :test_fn_traitd, trait : TraitD, struct :StEmpty");Self::test_fn_traita2();Self::test_fn_traitc(); // TraitCSelf::test_fn_traitb(); // TraitC 的爸爸Self::test_fn_traita(); // TraitC 的爷爷 - 都可以调用}}StEmpty::test_fn_traitd();
}//一个结构体有两个特性,他们的函数集有交集
fn test_10(){println!("---------test_10-------");trait TraitOne {fn action(&self) {println!("action of trait one!")}}trait TraitTwo {fn action(&self) {println!("action of trait two!");}}struct Person {}impl TraitOne for Person {}impl TraitTwo for Person {}let p = Person {};//p.action(); 编译失败,不支持这种调用方式<Person as TraitOne>::action(&p);<Person as TraitTwo>::action(&p);
}fn test_11() {/*trait特性之间的关联最初学习From和Into特性的时候,教程说只要实现了From特性就会自动实现Into特性,反之亦然。感觉很是奇怪,竟然还可以这样,今天我们看一个类似的例子:只要实现了GetName特性也就自动实现了PrintName特性,不知道From和Into是不是这么做的,这个以后有机会再研究把吧,*/trait GetName {fn get_name(&self) -> &String;}trait PrintName {fn print_name(&self);}//只要是实现了GetName特性的结构体,都可以实现PrintNameimpl<T: GetName> PrintName for T {fn print_name(&self) {println!("name = {}", self.get_name());}}///-----------------------下面是测试代码------------------struct Student {name: String,}impl GetName for Student {fn get_name(&self) -> &String {&(self.name)}}let s = Student {name: String::from("xiao ming"),};s.print_name();
}fn main() {test_1();test_2();test_3();test_4();test_5();test_6();test_7();test_8();test_9();test_9_2();test_10();test_11();
}

28.特性trait.rs相关推荐

  1. php之新特性trait详解

    废话不多说了,直接进入主题吧. 为什么要使用它,使用它有什么好处: 开发人员能够自由地在不同层次结构内独立的类中复用 method,在一定程度上弥补了单继承语言在某些情况下代码不能复用的问题. 与普通 ...

  2. android手机api等级_Android 9 API等级28特性(原创)

    显示屏缺口支持 全新的窗口布局,支持最新的全面屏,其中包含为摄像头和扬声器预留空间的屏幕缺口,让应用能充分利用每一块显示空间. 电源管理 Android 9引入了新功能以改善设备电源管理. 这些变更连 ...

  3. Rust学习资料大全

    2021年接触了区块链,接触了波卡,接触了rust,接触了一个全新的世界,愿自己可以有一个好的发展,加油!!!rust语言是一门新兴起的编程语言,作为一个编程爱好者很想把他学精学透.但是一门编程语言没 ...

  4. 3.type关键字.rs

    /* 你可以使用 type 关键字声明另一类型的别名(用法和C++一样一样的) 类型别名:type aliases type Name = String;type 也可以用来声明trait的关联类型, ...

  5. LVS DR模式负载均衡

    高并发场景 LVS 安装及高可用实现 分类: 运维基本功,故障解决 转载自 惨绿少年   https://www.cnblogs.com/clsn/p/7920637.html 1.1 负载均衡介绍 ...

  6. Rust的面向对象(五)——面向对象

    文章目录 Rust的面向对象(五)--面向对象 面向对象 封装 继承与多态(特性) Rust的面向对象(五)--面向对象 从1973年C语言主体完成到1983年C++正式命名,10年的时间,编程理念经 ...

  7. 基于java医院门诊管理系统设计

    获取项目源文件,学习交流联系Q:1415736481,可指导毕设,课设 [摘要]计算机信息技术应用于医院的日常管理,可以为医院的发展提供巨大的动力.本系统采SQL server2000为后台数据库,以 ...

  8. 大数据技术之_19_Spark学习_07_Spark 性能调优 + 数据倾斜调优 + 运行资源调优 + 程序开发调优 + Shuffle 调优 + GC 调优 + Spark 企业应用案例

    大数据技术之_19_Spark学习_07 第1章 Spark 性能优化 1.1 调优基本原则 1.1.1 基本概念和原则 1.1.2 性能监控方式 1.1.3 调优要点 1.2 数据倾斜优化 1.2. ...

  9. 对物联网通信技术原理的认知与理解

    目录 1.感知控制层通信的目的和特点: 2.网络传输层通信系统的设备和系统构成: 3.画出模拟通信系统和数字通信系统 : 4.通信的方式分类为: 5.数字通信和模拟通信的比较: 6.计算信源平均信息量 ...

最新文章

  1. ajax formdata提交上传,Ajax提交用FormData()上传文件
  2. 最大医学影像平台将首个实现把医疗AI引入实际应用
  3. 看下这段程序 ^_^
  4. 在Linux下编写并运行C文件
  5. 分布式事务seate-server的docker镜像的制作与部署
  6. jq获取input选取的文件名_tushare获取交易数据并可视化分析
  7. oracle对象权限 函数,oracle的系统和对象权限
  8. LaunchScreen原理
  9. oracle视图可以带日期变量么,创建视图时日期字段如何只都天
  10. python 实现两个excel表格数据的对比
  11. 2018_11_25_生活记录
  12. 用计算机亩换算成平方,亩换算(平方米换算亩计算器)
  13. (5)Scrum Master的7种武器之长生剑和孔雀翎
  14. halcon中的分水岭算法讲解以及作用和实例
  15. 微信公众号html怎么做的,微信公众平台页面模板怎么用?分类目录页面是如何制作的?...
  16. pacemaker+corosync+pg13
  17. 安卓开发常用的adb命令
  18. 2020-08-28
  19. spring:Failed to convert property value of type ‘java.lang.String‘ to required type ‘java.util.Date‘
  20. steam解锁未购买游戏工具

热门文章

  1. 进化之路:故事从两个线程说起
  2. SpringCloud_Sell.sql
  3. redis(19)--事务
  4. php 微信机器人_微信小程序机器人自动客服功能
  5. 【SpringBoot零基础案例05】【IEDA 2021.1】若SpringBoot项目两种配置文件同时存在,哪种文件配置起作用?
  6. vue axios 返回参数 响应参数
  7. 特朗普承诺改革H-1B签证 留住高技能外国人
  8. 日本社交餐厅评论服务平台Retty获1050万美元D轮融资
  9. VS2010+WinXP+MFC程序 无法定位程序输入点于动态链接库
  10. Cool Kitten:新鲜出炉的视差滚动 响应式框架