wxvirus wxvirus
首页
  • Go文章

    • Go语言学习
  • Rust

    • Rust学习
  • Java

    • 《Java》
  • Python文章

    • Python
  • PHP文章

    • PHP设计模式
  • 学习笔记

    • 《Git》
  • HTML
  • CSS
  • JS
  • 技术文档
  • GitHub技巧
  • 刷题
  • 博客搭建
  • 算法学习
  • 架构设计
  • 设计模式
  • 学习
  • 面试
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

无解的lifecycle

let today = new Beginning()
首页
  • Go文章

    • Go语言学习
  • Rust

    • Rust学习
  • Java

    • 《Java》
  • Python文章

    • Python
  • PHP文章

    • PHP设计模式
  • 学习笔记

    • 《Git》
  • HTML
  • CSS
  • JS
  • 技术文档
  • GitHub技巧
  • 刷题
  • 博客搭建
  • 算法学习
  • 架构设计
  • 设计模式
  • 学习
  • 面试
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • C&C++

  • PHP

  • Python

  • Go

  • microservice

  • rust

    • windows安装和配置
    • rust的第一个程序
    • cargo
    • 变量和基本类型
    • 函数和模块
    • 函数参数传递
    • 表达式和语句以及判断
    • 字符串练习
    • 自定义函数和模块的使用
    • 结构体入门和基本写法
    • trait入门
      • 定义实体类
      • 在函数中传 trait 作为参数
      • 在函数中传 2 个 trait 参数
      • 一个 struct 对应多个 trait
      • 操作符重载
    • 生命周期
    • Vector快速入门
    • 所有权以及所有权转移
    • 宏入门
    • 在struct中使用泛型
  • Java

  • 学习笔记

  • 后端
  • rust
wxvirus
2022-10-29

trait入门

# trait 入门

定义共享行为的接口设计。和java以及php里的抽象类或者接口类似。

目录层级

➜  mypro git:(dev_trait) ✗ tree -L 3
.
├── Cargo.lock
├── Cargo.toml
├── README.md
├── src
│   ├── api
│   │   ├── mod.rs
│   │   └── prods.rs
│   ├── lib
│   │   ├── config.rs
│   │   └── mod.rs
│   ├── main.rs
│   └── models
│       ├── book_model.rs
│       ├── mod.rs
│       └── user_model.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 定义实体类

定义一个Book的实体

// 图书实体

#[derive(Debug)]
pub struct Book {
    pub id: i32,
    pub price: f32,
}

// 所谓的实例化函数
pub fn new_book(id: i32, price: f32) -> Book {
    // 表达式
    Book {
        id: id,
        price: price,
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

同样的,必须在同级目录里的mod.rs里进行暴露,让外部可以使用

pub mod book_model;
pub mod user_model; // 这个是上一个demo里的内容
1
2

这次我们和上面写在实体里的方法不一样,我们另外新建一个src/api目录,里面包含一个mod.rs和一个商品的抽象接口或者抽象类

// 写成接口或抽象类

// crate 比 mod 级别更高
use crate::models::book_model::Book;

pub trait Prods {
    fn get_price(&self) -> f32;
}

// 使用 trait 对某一个 struct 定义方法
impl Prods for Book {
    fn get_price(&self) -> f32 {
        // 让价格加10元
        &self.price + 10.0
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

注意

这里我们需要使用外部的Book实体,就不能向main.rs里直接user目录层级下的即可,这里需要使用crate获取上一层,然后再去获取对应的实体。

这里的Prods就和java里的interface一样,只定义一个方法名,而且是以分号结尾,然后另外写方法实现。

main.rs调用,这里我们在mod.rs写成这样,方便我们理解

pub mod prods;
pub use prods::*;
1
2

直接在mod.rs里可以调用prods里的所有pub的内容;然后在main.rs里就不用use很多层。

mod api;
mod models;
use api::Prods;
use models::book_model::*;

fn main() {
    let book = new_book(101, 25.0);
    println!("{:?}", book.get_price());
}

1
2
3
4
5
6
7
8
9
10

use api::Prods;如果我们没有写pub use prods::*;,那么这里就得写成use api::prods::Prods;。

调用结果:

cargo build && cargo run

35.0
1
2
3

# 在函数中传 trait 作为参数

mod api;
mod models;
use api::Prods;
use models::book_model::*;

// 需要加上 impl 来说明它是 Prods 的trait
fn show_prod(p: impl Prods) {
    println!("商品的价格是: {}", p.get_price())
}

fn main() {
    // 需要指明具体的类型
    let book: Book = Prods::new(101, 25.0);
    println!("{:?}", book.get_price());
    show_prod(book)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

或者使用泛型,不过需要在函数名后面加上<泛型名称: 需要指明的trait>

mod api;
mod models;
use api::Prods;
use models::book_model::*;

fn show_prod<T: Prods>(p: T) {
    println!("商品的价格是: {}", p.get_price())
}

fn main() {
    // 需要指明具体的类型
    let book: Book = Prods::new(101, 25.0);
    println!("{:?}", book.get_price());
    show_prod(book)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 在函数中传 2 个 trait 参数

案例:计算商品的总价

我们在新增一个手机模型:phone_model.rs

#[derive(Debug)]
pub struct Phone {
    pub id: i32,
    pub price: f32,
}

1
2
3
4
5
6

不要忘了在mod.rs里进行引入。

pub mod book_model;
pub mod phone_model;
pub mod user_model;

1
2
3
4

继续使用Prods实现Phone的 2 个方法

// 写成接口或抽象类

// crate 比 mod 级别更高
use crate::models::book_model::Book;
use crate::models::phone_model::Phone;

pub trait Prods {
    fn get_price(&self) -> f32;
    fn new(id: i32, price: f32) -> Self;
}

// 使用 trait 对某一个 struct 定义方法
impl Prods for Book {
    fn get_price(&self) -> f32 {
        &self.price + 10.0
    }

    fn new(id: i32, price: f32) -> Book {
        Book { id, price }
    }
}

impl Prods for Phone {
    fn new(id: i32, price: f32) -> Phone {
        Phone { id, price }
    }
    fn get_price(&self) -> f32 {
        &self.price + 20.0
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

实践:

mod api;
mod models;
use api::Prods;
use models::{book_model::*, phone_model::Phone};

fn sum1<T: Prods>(p1: T, p2: T) {
    println!("商品总价是: {}", p1.get_price() + p2.get_price())
}

fn sum2<T: Prods, U: Prods>(p1: T, p2: U) {
    println!("商品总价是: {}", p1.get_price() + p2.get_price())
}

fn main() {
    // 需要指明具体的类型
    let book1: Book = Prods::new(101, 25.6);
    let book2: Book = Prods::new(102, 30.6);
    sum1(book1, book2);
    let book3: Book = Prods::new(103, 10.3);
    let phone1: Phone = Prods::new(104, 1300.2);
    sum2(book3, phone1);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
➜  mypro git:(dev_trait) ✗ cargo build && cargo run
   Compiling mypro v0.1.0 (/Users/wangxin/workspace/rustworkspace/mypro)
    Finished dev [unoptimized + debuginfo] target(s) in 0.23s
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/mypro`
商品总价是: 76.2
商品总价是: 1340.5
1
2
3
4
5
6
7

# 一个 struct 对应多个 trait

在写一个Stock的trait

use crate::models::book_model::Book;
pub trait Stock {
    fn get_stock(&self) -> i32;
}

impl Stock for Book {
    fn get_stock(&self) -> i32 {
        123
    }
}

1
2
3
4
5
6
7
8
9
10
11

多个就需要指定多个的trait

mod api;
mod models;
use api::Prods;
use api::Stock;
use models::book_model::*;

fn show_detail<T: Prods + Stock>(p: T) {
    println!("商品的库存是: {}", p.get_stock());
}

fn main() {
    // 需要指明具体的类型
    let book1: Book = Prods::new(101, 25.6);
    show_detail(book1);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

或者使用where来简写

fn show_detail<T>(p: T)
where
    T: Prods + Stock,
{
    println!("商品的库存是: {}", p.get_stock());
}
1
2
3
4
5
6

# 操作符重载

简单实现了一个 2 个商品的价格相加的方法

mod api;
mod models;
use api::Prods;
use api::Stock;
use models::book_model::*;

fn sum(p1: Book, p2: Book) {
    println!("商品总价是: {}", p1.get_price() + p2.get_price());
}

fn main() {
    // 需要指明具体的类型
    let book1: Book = Prods::new(101, 25.6);
    let book2: Book = Prods::new(110, 30.5);
    sum(book1, book2);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

它这里无法实现

println!("商品总价是: {}", p1 + p2);
1

所以我们要对这个加号进行重载,加号是在标准库std::ops::Add方法,它也是一个trait

源码内容:

#[doc(alias = "+")]
pub trait Add<Rhs = Self> {
    /// The resulting type after applying the `+` operator.
    #[stable(feature = "rust1", since = "1.0.0")]
    type Output;

    /// Performs the `+` operation.
    ///
    /// # Example
    ///
    /// ```
    /// assert_eq!(12 + 1, 13);
    /// ```
    #[must_use]
    #[stable(feature = "rust1", since = "1.0.0")]
    fn add(self, rhs: Rhs) -> Self::Output;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

我们在prods.rs里进行重载编写:

impl std::ops::Add<Book> for Book {
    // 定义输出类型是什么
    type Output = f32;
    // 实现加法 A, B B的类型为对应的book类型
    fn add(self, rhs: Book) -> f32 {
        self.get_price() + rhs.get_price()
    }
}
1
2
3
4
5
6
7
8

然后我们就可以实现p1+p2这种形式的加法

mod api;
mod models;
use api::Prods;
use api::Stock;
use models::book_model::*;

fn sum(p1: Book, p2: Book) {
    println!("商品总价是: {}", p1 + p2);
}

fn main() {
    // 需要指明具体的类型
    let book1: Book = Prods::new(101, 25.6);
    let book2: Book = Prods::new(110, 30.5);
    sum(book1, book2);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cargo build && cargo run

商品总价是: 76.1
1
2
3

注意

不要被这里的加法的结果给误导了,因为我们上面有一个get_price的方法里面是给价格加了 10 的,所以这里的结果可能就不是直白的两个数值相加的结果。

稍微给sum函数变通一下就是

fn sum(p1: Book, p2: Book) {
    println!(
        "p1的价格是: {}, p2的价格是: {}, 商品总价是: {}",
        p1.get_price(),
        p2.get_price(),
        p1 + p2
    );
}
1
2
3
4
5
6
7
8
cargo build && cargo run

p1的价格是: 35.6, p2的价格是: 40.5, 商品总价是: 76.1
1
2
3
编辑 (opens new window)
#trait
上次更新: 2022/11/06, 16:58:13
结构体入门和基本写法
生命周期

← 结构体入门和基本写法 生命周期→

最近更新
01
vue3配合vite初始化项目的一些配置
07-26
02
网盘系统开发学习
07-24
03
linux多进程
06-19
更多文章>
Theme by Vdoing | Copyright © 2021-2024 wxvirus 苏ICP备2021007210号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式