rust学习十一.2、使用Trait(特质)定义通用类型的共同举动 ...

打印 上一主题 下一主题

主题 906|帖子 906|积分 2718

Trait 本意是特性,特质,特性等等,其实重要指人的性格特性。不明白为什么rust的创造者不使用feature这样单词。
 
如作者所言:
Note: Traits are similar to a feature often called interfaces in other languages, although with some differences.
特性类似于别的语言的接口,但和接口还是有一些区别的。
为了便于行文,本文把Trait翻译为特质
 
我查了一些资料,可以确认这句话基本上是对的。不对的在那里了?此处先不聊了。  总之特质在大部分情况下可以当做接口即可。
但是不能把特质称为接口,由于接口仅仅是特质的一个功能,它另有别的作用。
 
本文的内容重要都是为了通用类型服务,前面讲了许多接口特质的内容。
从本章开始,可以看到越来越多奇奇怪怪的语法,虽然我已经学过不少语言,但Rust绝对是此中的奇葩!
一、如何定义一个接口特质

所谓接口特质,即作为接口使用的特质。
就一个步骤:
  1. pub trait Work{
  2.     fn design(&self);
  3.     fn code(&self);
  4.     fn test(&self);
  5. }
复制代码
 
1.pub修饰符可选
2.一个接口特质中可以定义多个方法
这和大部分语言差不多。
二、为结构体实现一个接口特质

2.1基本实现

实现一个接口特质也很简朴,使用impl语法:
trait Summary {    fn summarize(&self) -> String;    fn get_content(&self) -> &String;    fn is_empty(&self) -> bool {        self.get_content().is_empty()    }}struct Tweet {    pub username: String,    pub content: String,    pub reply: bool,    pub retweet: bool,    pub time: String}
impl Summary for Tweet {    fn summarize(&self) -> String {        format!("{}: {}  -- {}", self.username, self.content,self.time)    }    fn get_content(&self) -> &String {        &self.content    }}
fn main(){    let tweet = Tweet {        username: String::from("勒布朗.詹姆斯"),        content: String::from("我,要退网!"),        reply: false,        retweet: false,        time: String::from("2024-11-21 05:01:01")    };    println!("{}", tweet.summarize());} 几个注意事项:
1.当实现一个接口特质的时候,必须实现这个接口特质中的所有方法,不能只有一部分
2.不能越界实现别的单位包中的接口特质。例如在单位包a存在接口特质 Ta,那么无法在单位包b中实现Ta
如果违反了,会提示:only traits defined in the current crate can be implemented for types defined outside of the crate
define and implement a trait or new type instead
3.如果接口特质T在当前单位包,那么无论对象(结构体、枚举等)O位于那里,那么都可以为O实现T
4.在同一个单位包内,你不能在差别模块为同个对象实现多次接口特质
以上第2条并不是普适的。rust的一些特质是位于标准库中,但答应你在本身的模块中实现这些接口特质,典型的是Display
2.2 默认实现

和java一样(从J8开始),rust也提供了默认实现,只不过java把接口搞得更加复杂一些。
  1. trait Summary {
  2.     fn summarize(&self) -> String;
  3.     fn get_content(&self) -> &String;
  4.     fn is_empty(&self) -> bool {
  5.         self.get_content().is_empty()
  6.     }
  7. }
复制代码
方法is_empty就是默认的实现。这样在实今世码中,不需要提供is_empty有关的代码,也可以正常使用:
  1. trait Summary {
  2.     fn summarize(&self) -> String;
  3.     fn get_content(&self) -> &String;
  4.     fn is_empty(&self) -> bool {
  5.         self.get_content().is_empty()
  6.     }
  7. }struct NewsArticle {    pub headline: String,    pub location: String,    pub author: String,    pub content: String}impl Summary for NewsArticle {    fn summarize(&self) -> String {        format!("{}, by {} ({}) \n {}", self.headline, self.author, self.location,self.content)    }    fn get_content(&self) -> &String {        &self.content    }}fn main(){    let news= NewsArticle {        headline: String::from("英雄纪念碑"),        location: String::from("中国北京"),        author: String::from("新华社记者m--泽--东"),        content: String::from("由此上溯到一千八百四十年,从那时起,为了反对内外敌人,        争取民族独立和人民自由幸福,在历次斗争中捐躯的人民英雄们永垂不朽!")    };    println!("{}", news.summarize());    println!("{}", news.is_empty());    }
复制代码
 
默认方法是否可以覆盖了?可以的,这个和java也一样:
  1. impl Summary for NewsArticle {
  2.     fn summarize(&self) -> String {
  3.         format!("{}, by {} ({}) \n {}", self.headline, self.author, self.location,self.content)
  4.     }
  5.     fn get_content(&self) -> &String {
  6.         &self.content
  7.     }
  8.     fn is_empty(&self) -> bool {
  9.         println!("{}", self.content.len());
  10.         self.content.len()<1000
  11.     }
  12. }
复制代码
 
 
四、返回接口特质

和别的语言类似,但是这个有个题目:rust编译器只把返回的当作接口特质,而不是当作具体的对象(结构体或者枚举)。
以是,如果没有类似别的语言的强制转换,或者编译器支持,企图把返回的接口特质当作某个对象,那是不可的。
  1. fn print(article:&impl Summary){
  2.     println!("{}", article.get_content());
  3. }
复制代码
 
上例中,为什么my_tube.vol会陈诉非常,是由于rust编译器的逻辑只认为my_tube是一个接口特质,以是my_tube不能调用Tube的属性/方法,但是
my_tube可以调用Brush的具体方法。
 
五、资助实现通用类型函数/方法

前面的一堆内容就是为了两个目的:如何定义和实现接口特质;如何在通用类型方法中限定参数的范围。
“如何定义和实现”基本上都明白了,现在就示例下如何实现“通用类型参数限定范围”。
方式是:使用接口特质
语法: 或者,或者也可以使用where字句
  1. /**
  2. * 使用<T:t>的方式,是impl trait的方式的正规形式。  
  3. * 即print_normal是print的正规形式
  4. */
  5. fn print_normal<T:Summary>(article:&T){
  6.     println!("使用<T:t>的方式:{}", article.get_content());
  7. }
复制代码
 
六、小结


  • 接口特质是特质的一个部分,不能把特质翻译为接口
  • 定义接口特质还是比较简朴的。可以在一个接口特质中定义多个方法。
  • 不能在当前单位包中实现在别的单位包中定义的接口特质。但是存在例外情况,例如一些rust位于标准库中的接口特质;一个单位包内,不能在差别模块为一个接口特质,一个对象做n次实现
  • 接口特质的方法可以有默认实现;默认实现的方法可以被覆盖
  • 在方法中可以使用接口特质作为参数。有两种方式:impl,标准。前者不会强制所有参数同个类型,后者会
  • 还可以使用where字句来限定参数的接口特质。
  • 某个参数如果要绑定(限定)多个接口,可以使用+符号
  • 接口特质的出现,使得定义参数,方法变得更加灵活,也更加复杂
  • 函数/方法可以返回接口特质,但如果没有特别措施,不能把返回的效果当作具体类型使用。编译器只会把返回效果当值接口特质,即使你在方法体中明确返回的类型。
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

卖不甜枣

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表