Trait 特质
Trait是一种定义方法签名的机制,特质允许你定义一组方法的签名,但可以不提供具体的方法实现
任何类型都可以实现特质,只要他们提供了特质中定义的所有方法。这是的你可以为不同类型提供相同的行为
-
内置常量:const,整个生命周期都是有效的
-
默认实现
-
多重实现:类型可以实现多个trait,可以将不同行为组合在一起
-
trait边界:在泛型代码中,使用特质作为类型约束
-
trait alias:可以创建简介的别名
trait Greeter {
fn greet(&self);
fn hello() {
println!("hello");
}
}
struct Person {
name: String,
}
impl Greeter for Person {
fn greet(&self) {
println!("{}", self.name);
}
}
fn main(){
let person = Person {
name: "moguw".to_owned(),
};
Person::hello();
person.greet();
}
Trait Object 与 Box
Trait Object
-
在运行时动态分配的对象
“运行时泛型”
比泛型要灵活的多 -
可以在集合中混入不同的类型对象
更容易处理相似的数据 -
有一些小小的性能损耗
dyn关键字
dyn是Rust中的关键字,用于声明trait object的类型。trait object是实现了trait的类型的实例,但其具体类型在编译时是未知的。因此为了让编译器知道我们正在处理的是trait object,我们需要在trait名称前面加上dyn关键字
dyn关键字的作用是:指示编译器处理trait object
Rust中数据传输的三种形式
不可变引用 &dyn Trait
可变引用 &mut dyn Trait
Move与以所有权转移:特指需要用Box
特质与Box
创建trait object的三种方式
let o = Object{}
let o_obj: &dyn Object = &o
let o_obj: &dyn Object = &Object {};
let o_obj: Box<dyn Object> = Box::new(Object{})
// trait 不可变引用
struct Obj {}
trait Overview{
fn overview(&self) -> String {
String::from("overview")
}
}
impl Overview for Obj{
fn overview(&self) -> String {
String::from("Obj")
}
}
// 不可变引用
fn call_obj(item: &impl Overview) {
println!("Overview {}", item.overview());
}
// Move
fn call_obj_box(item: Box<dyn Overview>) {
println!("Overview {}", item.overview());
}
trait Sale {
fn amount(&self) -> f64;
}
struct Common(f64); // 原始金额
impl Sale for Common{
fn amount(&self) -> f64 {
self.0
}
}
struct TenDiscount(f64);
impl Sale for TenDiscount {
fn amount(&self) -> f64 {
self.0 - 10.
}
}
struct TenPercentDiscount(f64);
impl Sale for TenPercentDiscount {
fn amount(&self) -> f64 {
self.0 * 0.9
}
}
fn calculate(sales: &Vec<Box<dyn Sale>>) -> f64 {
sales.iter().map(|sale| sale.amount()).sum()
}
fn main() {
let a = Obj{};
call_obj(&a);
println!("{}", a.overview());
let b_a = Box::new(Obj {});
call_obj_box(b_a); // 所有权转移
let c: Box<dyn Sale> = Box::new(Common(100.));
let d: Box<dyn Sale> = Box::new(TenDiscount(100.));
let e: Box<dyn Sale> = Box::new(TenPercentDiscount(100.));
let sales = vec![c, d, e]; // : Vec<Box<dyn Sale>>
println!("pay {}", calculate(&sales));
}
Trait Object 与 泛型
泛型与impl不同的写法
// 可以是不同类型
fn call(item1: &impl Trait, item2: &impl Trait);
// 一定是相同类型
fn call_generic<T: Trait>(item1: &T, item2: &T);
// multiple trait bound
fn call(item1: &(impl Trait+AnotherTrait));
fn call_genertic<T: Trait+AnotherTrait>(item: &T);
trait Overview {
fn overview(&self) -> String {
String::from("Course")
}
}
trait Another {
fn hell(&self) {
println!("Welcome to hell");
}
}
struct Course {
headline: String,
author: String,
}
impl Overview for Course {}
impl Another for Course {}
struct AnotherCourse {
headline: String,
author: String,
}
impl Overview for AnotherCourse {}
fn call_overview(item: &impl Overview) {
println!("Overview");
}
fn call_overview_generic<T: Overview>(item: &T) {
println!("Overview");
}
fn call_overviewT(item1: &impl Overview, item2: &impl Overview) {
println!("Overview {}",item1.overview());
println!("Overview {}",item2.overview());
}
fn call_overviewTT<T: Overview>(item1: &T, item2: &T) {
println!("Overview {}",item1.overview());
println!("Overview {}",item2.overview());
}
// 多绑定
fn call_mul_bind(item: &(impl Overview + Another)) {
println!("Overview {}",item.overview());
item.hell();
}
// 多绑定
fn call_mul_bindT<T>(item: &T)
where
T: Overview+Another
{
println!("Overview {}",item.overview());
item.hell();
}
fn main() {
let c1 = Course{
headline: "11".to_owned(),
author: "22".to_owned()
};
let c2 = AnotherCourse{
headline: "11".to_owned(),
author: "22".to_owned()
};
let c3 = Course{
headline: "11".to_owned(),
author: "22".to_owned()
};
call_overview(&c1);
call_overview_generic(&c1);
println!("------");
call_overviewT(&c1, &c2);
call_overviewTT(&c1, &c3);
println!("------");
call_mul_bind(&c1);
call_mul_bindT(&c3);
}
重载操作符
只需要实现相对的特质即可
use std::ops::Add;
// 编译时确定
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
// T 可以执行相加的操作
impl<T> Add for Point<T>
where
T: Add<Output = T>
{
type Output = Self;
fn add(self,rhs: Self) -> Self::Output{
Point {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
fn main(){
let i1 = Point {
x: 0,
y: 0,
};
let i2= Point {
x: 1,
y: 1,
};
let sum = i1 + i2;
println!("{:?}", sum);
}
Trait多态和继承
Rust并不支持传统的继承的概念,但是可以在特质中通过层级化来完成需求
Rust选择了一种函数式编程的范式,即“组合与委托”而并不是继承
编程语言的大势也是组合由于继承
-
多态是面向对象编程中的一个重要概念,指的是同一个方法调用可以根据对象的不同类型而表现出不同的行为。简单来说,多态允许一个接口或方法在不同的上下文中表现出不同的行为。这样做的好处是可以提高代码的灵活性和可扩展性,使得代码更易于维护和理解
-
Rust中的多态无处不在
use std::collections::VecDeque;
trait Driver {
fn drive(&self);
}
struct Car;
impl Driver for Car {
fn drive(&self) {
println!("Car is driving");
}
}
struct SUV;
impl Driver for SUV {
fn drive(&self) {
println!("SUV is driving");
}
}
fn road(vehicle: &dyn Driver) {
vehicle.drive();
}
trait Queue {
fn len(&self) -> usize;
fn push_back(&mut self, n: i32);
fn pop_front(&mut self) -> Option<i32>;
}
trait Double: Queue {
fn push_front(&mut self, n: i32);
fn pop_back(&mut self) -> Option<i32>;
}
#[derive(Debug)]
struct list {
data: VecDeque<i32>,
}
impl list {
fn new() -> Self {
let data = VecDeque::<i32>::new();
Self { data }
}
}
impl Double for list {
fn push_front(&mut self, n:i32) {
self.data.push_front(n)
}
fn pop_back(&mut self) -> Option<i32> {
self.data.pop_back()
}
}
impl Queue for list {
fn len(&self) -> usize {
self.data.len()
}
fn push_back(&mut self, n: i32) {
self.data.push_back(n)
}
fn pop_front(&mut self) -> Option<i32> {
self.data.pop_front()
}
}
fn main() {
road(&Car);
road(&SUV);
let mut l = list::new();
l.push_back(1);
l.push_front(0);
println!("{:?}", l);
l.push_front(2);
println!("{:?}", l);
l.push_back(2);
println!("{:?}", l);
println!("{}", l.pop_back().unwrap());
println!("{:?}", l);
}
常见的Trait
#[derive(Debug, Clone, Copy)]
enum Race {
White,
Yellow,
Black
}
impl PartialEq for Race {
fn eq(&self, other: &Self) -> bool {
match(self, other) {
(Race::White, Race::White) => true,
(Race::Yellow, Race::Yellow) => true,
(Race::Black, Race::Black) => true,
_ => false,
}
}
}
#[derive(Debug, Clone)]
struct User {
id: u32,
name: String, // String不实现COpy
race: Race,
}
impl PartialEq for User {
fn eq(&self, other: &Self) -> bool {
self.id == other.id && self.name == other.name && self.race == other.race
}
}
fn main() {
let user = User {
id: 3,
name: "John".to_owned(),
race: Race::Yellow,
};
println!("{:#?}", user);
let user1 = user.clone();
println!("{:#?}", user1);
println!("{:#?}", user==user1);
}
标签:入门,Overview,self,简易,let,Rust,println,fn,impl
From: https://www.cnblogs.com/moguw/p/18143717/rust-base-6