Rust特征
一、Rust特征是什么、怎么用
1、Rust特征是什么
我认为Rust特征和Java中的接口类似,但是扩展了语义
特征定义了一组可以被共享的行为,只要实现了特征,你就能使用这组行为
2、Rust特征怎么使用
(1)特征定义
pub trait Summary {//Summary 是特征名称
fn summarize(&self) -> String;//和接口类似,不需要具体实现方法体
}
带有默认实现的特征定义
pub trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}
这样使得实现了该特征的类型,自动具备了默认的特征行为,当然也可以覆盖重写,优先调用覆盖重写的特征行为
(2)为类型实现特征
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct Post {//类型可以不仅仅是结构体,是 类型 就可以定义特征
pub title: String, // 标题
pub author: String, // 作者
pub content: String, // 内容
}
impl Summary for Post {
fn summarize(&self) -> String {
format!("文章{}, 作者是{}", self.title, self.author)
}
}
pub struct Weibo {
pub username: String,
pub content: String
}
impl Summary for Weibo {//为Weibo 实现特征Summary,则Weibo具有Summary的特征和对应特征的行为
fn summarize(&self) -> String {
format!("{}发表了微博{}", self.username, self.content)
}
}
fn main() {
let post = Post{title: "Rust语言简介".to_string(),author: "Sunface".to_string(), content: "Rust棒极了!".to_string()};
let weibo = Weibo{username: "sunface".to_string(),content: "好像微博没Tweet好用".to_string()};
println!("{}",post.summarize());
println!("{}",weibo.summarize());
}
为类型实现特征之后,我们来调用对应特征的行为来看看
文章Rust语言简介, 作者是Sunface
sunface发表了微博好像微博没Tweet好用
这样我们就完成了特征的基本定义和使用
(3)使用特征作为函数参数
这时候感觉特征有点多态的味道了,但不是Java继承的那种多态,像是Golang的那种组合多态。
可以使用任何实现了 Summary 特征的类型作为该函数的参数
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct Post {
pub title: String, // 标题
pub author: String, // 作者
pub content: String, // 内容
}
impl Summary for Post {
fn summarize(&self) -> String {
format!("文章{}, 作者是{}", self.title, self.author)
}
}
pub struct Weibo {
pub username: String,
pub content: String
}
impl Summary for Weibo {
fn summarize(&self) -> String {
format!("{}发表了微博{}", self.username, self.content)
}
}
fn main() {
let post = Post{title: "Rust语言简介".to_string(),author: "Sunface".to_string(), content: "Rust棒极了!".to_string()};
notify(&post);
}
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
如果我们用特征作为返回值会怎么样呢,后面我们在讨论这件事情
(4)特征约束
其实impl Summary就是特质约束的一种语法糖写法,约束了你传递的参数需要实现Summary特征。
当然还可以是别的写法,形如 T: Summary 被称为特征约束,例如:
pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}
如果涉及多个约束条件,那么我们可以这么写
pub fn notify(item: &(impl Summary + Display)) {}//Summary和Display两个约束
pub fn notify<T: Summary + Display>(item: &T) {}
fn some_function<T, U>(t: &T, u: &U) -> i32
where T: Display + Clone,
U: Clone + Debug
{}
前面的写法意义上是一样的,只是语法不同。
(5)使用特征约束有条件地实现方法或特征
特征约束,可以让我们在指定类型 + 指定特征的条件下去实现方法,例如:
use std::fmt::Display;
struct Pair<T> {
x: T,
y: T,
}
impl<T> Pair<T> {
fn new(x: T, y: T) -> Self {
Self {
x,
y,
}
}
}
impl<T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x >= self.y {
println!("The largest member is x = {}", self.x);
} else {
println!("The largest member is y = {}", self.y);
}
}
}
上面代码的意思是
cmp_display 方法,并不是所有的 Pair 结构体对象都可以拥有,只有 T 同时实现了 Display +
PartialOrd 的 Pair 才可以拥有此方法
(5)派生特征(引入特征)
形如 #[derive(Debug)] ,这种是一种特征派生语法,被 derive 标记的对象会自动实现对应的默认特征代码,继承相应的功能。
// 为Centimeters引入结构体比较的特征,使得Centimeters可以进行比较
#[derive(PartialEq, PartialOrd)]
struct Centimeters(f64);
// 为Inches引入结构体打印的特征
#[derive(Debug)]
struct Inches(i32);
impl Inches {
fn to_centimeters(&self) -> Centimeters {
let &Inches(inches) = self;
Centimeters(inches as f64 * 2.54)
}
}
// 引入结构体打印、结构体比较的特征功能
#[derive(Debug,PartialEq,PartialOrd)]
struct Seconds(i32);
fn main() {
let _one_second = Seconds(1);
println!("One second looks like: {:?}", _one_second);
let _this_is_true = (_one_second == _one_second);
let _this_is_false = (_one_second > _one_second);
let foot = Inches(12);
println!("One foot equals {:?}", foot);
let meter = Centimeters(100.0);
let cmp =
if foot.to_centimeters() < meter {
"smaller"
} else {
"bigger"
};
println!("One foot is {} than one meter.", cmp);
}
(6)使用特征作为返回参数?
前面我们提到了特征可以参数函数参数进行传递,实现了类似Golang组合继承的效果,如果我们采用特征作为返回参数可以吗?
来看一段代码
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct Post {
pub title: String, // 标题
pub author: String, // 作者
pub content: String, // 内容
}
impl Summary for Post {
fn summarize(&self) -> String {
format!("文章{}, 作者是{}", self.title, self.author)
}
}
pub struct Weibo {
pub username: String,
pub content: String
}
impl Summary for Weibo {
fn summarize(&self) -> String {
format!("{}发表了微博{}", self.username, self.content)
}
}
fn returns_summarizable(switch: bool) -> impl Summary {
if switch {
Post {
title: String::from(
"Penguins win the Stanley Cup Championship!",
),
author: String::from("Iceburgh"),
content: String::from(
"The Pittsburgh Penguins once again are the best \
hockey team in the NHL.",
),
}
} else {
Weibo {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
}
}
}
fn main() {
_a =returns_summarizable(true);
}
上面代码中,Weibo和Post都已经实现了Summary特征,运行一下
`if` and `else` have incompatible types
expected struct `Post`, found struct `Weibo`
报错提示我们 if 和 else 返回了不同的类型。只有相同类型,才可以使用imply trait的方式。如果想要实现返回 “实现相同特征”的 “不同的类型”,需要使用特征对象,下一篇我们再讲特征对象
原文地址:https://blog.csdn.net/vince1998/article/details/138273734
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!