rust中的“继承”
文章目录
- 前言
- rust结构体组合
- 公共结构体提取
- 其他结构体中使用
- 使用方法
- 使用过程宏
- 宏定义
- 结构体中使用
- 使用方法
- rust编译执行过程
- 查看过程宏生成的代码
- 结语
前言
我是从第一门语言学习的是C#,在C#中子类可以继承基类,老鸟都给我们说学会了一门语言学第二门就简单了基本都是相通的,但当我看到rust的时候发现是相通,当通的有点差异。下面我就来给大家风险一下,C#中的继承在Rust中的差异
rust结构体组合
C#中也有结构体这个类型,这一点他们是相同的,只是语法上有一点点差异,在rust中结构体是不支持继承的,具体原因是因为Rust 的结构体是“值语义 + 内存布局固定”,一旦允许继承就会破坏这两件事
下面我们来看一下应用场景
(Rust代码)
///用户信息
pub struct User {pub id: i32,pub create_at: DateTime<Local>,pub update_at: DateTime<Local>,pub delete_at: DateTime<Local>,pub is_deleted: bool,pub name: String,pub email: String,
}
///汽车信息
pub struct Car {pub id: String,pub create_at: DateTime<Local>,pub update_at: DateTime<Local>,pub delete_at: DateTime<Local>,pub is_deleted: bool,pub car_number: String,
}
根据上面的结构体我们可以发现这两个结构体他们都拥有相同的字段;为了减少代码的冗余我们可以把他们提取出来,做成一个“基类”然后子类继承它就可以了。在C#中当然可以这样做,但是rust中不行,rust中是可以把它提取出来,但是是把它提取出来作为一个新的结构体,然后子结构体中再包含这个公共的结构体。
公共结构体提取
提取出来的公共结构体如下:
///公共属性
pub struct BaseModel<T> {///主键idpub id: T,pub create_at: DateTime<Local>,pub update_at: DateTime<Local>,pub delete_at: DateTime<Local>,pub is_deleted: bool,
}
impl<T> BaseModel<T> {///实现构造函数fn new(id: T,create_at: DateTime<Local>,update_at: DateTime<Local>,delete_at: DateTime<Local>,is_deleted: bool,) -> Self {Self {id,create_at,update_at,delete_at,is_deleted,}}
}
其他结构体中使用
///用户信息
pub struct User {pub base:BaseModel<i32>,pub name: String,pub email: String,
}
impl User {///实现构造函数pub fn new(base: BaseModel<i32>, name: String, email: String) -> Self {Self{base,name,email,}}
}
///汽车信息
pub struct Car {pub base:BaseModel<String>,pub car_number: String,
}
impl Car{///实现构造函数pub fn new(base: BaseModel<String>,car_number: String) -> Self {Self{base,car_number}}
}
使用方法
fn main() {let now = Local::now();let base_user = BaseModel::new(1,now,now,now,false);let user=User::new(base_user,"test".to_string(),"test".to_string());println!("用户的创建时间:{}",user.base.create_at.to_string());let base_car=BaseModel::new("GUID".to_string(),now,now,now,false);let car=Car::new(base_car,"test".to_string());println!("汽车的id:{}",car.base.id.to_string());
}
执行结果如下:
使用过程宏
使用过程宏会是代码变得抽象,不便于阅读和调试,但是如果真想偷懒的话也可以用一用
宏定义
use chrono::Local;
#[macro_export]
macro_rules! define_model {($struct_name:ident<$ty:ident> { $($field:ident: $field_ty:ty),* $(,)? }) => {#[derive(Debug)]pub struct $struct_name<$ty> {pub id: $ty,pub create_at: ::chrono::DateTime<::chrono::Local>,pub update_at: ::chrono::DateTime<::chrono::Local>,pub delete_at: ::chrono::DateTime<::chrono::Local>,pub is_deleted: bool,$(pub $field: $field_ty,)*}impl<$ty> $struct_name<$ty> {pub fn new(id: $ty,create_at: ::chrono::DateTime<::chrono::Local>,update_at: ::chrono::DateTime<::chrono::Local>,delete_at: ::chrono::DateTime<::chrono::Local>,is_deleted: bool,$($field: $field_ty,)*) -> Self {Self {id,create_at,update_at,delete_at,is_deleted,$($field,)*}}}};
}
结构体中使用
define_model!(User<T> {name: String,email: String,
});
define_model!(Car<T> {car_number: String,
});
使用方法
fn main() {let now = Local::now();let user: User<i64> = User::new(1i64, now, now, now, false,"test".to_string(),"12323@qq.com".to_string());let car=Car::new("GUID".to_string(),now,now,now,false,"9999".to_string());println!("{:?}",car);println!("{:?}",user);
}
执行效果如下
图片可能看不太清除,它打印的结果如下:
PS D:\Code\Rust\测试程序\test_struct> cargo runCompiling test_struct v0.1.0 (D:\Code\Rust\测试程序\test_struct)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.44sRunning `target\debug\test_struct.exe`
Car { id: "GUID", create_at: 2025-09-17T10:57:13.230130300+08:00, update_at: 2025-09-17T10:57:13.230130300+08:00, delete_at: 2025-09-17T10:57:13.230130300+08:00, is_deleted: false, car_number: "9999" }
User { id: 1, create_at: 2025-09-17T10:57:13.230130300+08:00, update_at: 2025-09-17T10:57:13.230130300+08:00, delete_at: 2025-09-17T10:57:13.230130300+08:00, is_deleted: false, name: "test", email: "12323@qq.com" }
很明显两个结构体中都包含的公共结构体中的字段。其实过程宏简单理解就是代码生成器,在编译的时候他会把代码生成好放入实体中,在编写程序时还是要尽可能少的使用
过程宏,它会使阅读代码变得困难。
rust编译执行过程
源码↓ 词法/解析TokenStream↓AST(抽象语法树)├─ ➤ 过程宏/声明宏展开(我们定义的过程宏在这里执行)└─ ➤ 名称解析、early lintAST↓ loweringHIR(高级中间表示)↓类型检查、trait 求解↓MIR(中级中间表示)↓LLVMIR↓二进制执行文件
查看过程宏生成的代码
查看过程宏生成的代码可以使用 cargo expand
首先需要执行以下命令安装它
cargo install cargo-expand
结语
rust学习起来会让你更了解程序底层的运行逻辑,很适合作为第二门学习语言。