Rust 虽然不是纯粹的面向对象编程语言,但它通过结构体(struct)、枚举(enum)、特质(trait)等特性支持面向对象编程(OOP)的核心概念,如封装、继承和多态。以下是 Rust 面向对象编程的完整实现与说明:
代码说明
1. 封装(Encapsulation)
-
实现方式:通过结构体的私有字段和公共方法实现
-
示例解析:
BankAccount
结构体的字段(account_number
、balance
、owner
)都是私有的,无法直接访问- 提供公共方法(
deposit
、withdraw
、get_balance
等)来操作和访问这些字段 - 方法内部可以进行数据验证(如确保存款金额为正数),保证数据完整性
2. 继承与多态(通过特质实现)
-
特质(Trait) :类似其他语言的接口,定义了一组方法签名
Shape
特质定义了所有形状都应具备的方法(area
、perimeter
、name
)
-
多态实现:
- 不同结构体(
Circle
、Rectangle
)可以实现同一个特质 print_shape_info
函数接受&dyn Shape
参数,可以处理任何实现了Shape
特质的对象- 运行时会根据实际对象类型调用相应的方法实现
- 不同结构体(
3. 特质对象(Trait Objects)
Box<dyn Shape>
是一个特质对象,允许在向量中存储不同类型但实现了相同特质的对象- 特质对象实现了动态分发(dynamic dispatch),在运行时确定调用哪个方法实现
4. 组合(Composition)
- Rust 更推荐使用组合而非传统的继承
Drawing
结构体包含了一个形状的集合,通过组合实现了更灵活的功能- 这种方式避免了继承带来的复杂性,同时保持了代码的灵活性和可维护性
main.rs 代码
rust
// 1. 封装(Encapsulation):使用结构体和访问控制实现
// 定义一个具有私有字段和公共方法的结构体
pub struct BankAccount {
account_number: String, // 私有字段
balance: f64, // 私有字段
owner: String, // 私有字段
}
impl BankAccount {
// 构造函数(关联函数)
pub fn new(account_number: String, owner: String) -> Self {
BankAccount {
account_number,
balance: 0.0,
owner,
}
}
// 公共方法:存款
pub fn deposit(&mut self, amount: f64) -> Result<(), String> {
if amount <= 0.0 {
return Err("存款金额必须为正数".to_string());
}
self.balance += amount;
Ok(())
}
// 公共方法:取款
pub fn withdraw(&mut self, amount: f64) -> Result<(), String> {
if amount <= 0.0 {
return Err("取款金额必须为正数".to_string());
}
if amount > self.balance {
return Err("余额不足".to_string());
}
self.balance -= amount;
Ok(())
}
// 公共方法:查询余额(封装私有字段的访问)
pub fn get_balance(&self) -> f64 {
self.balance
}
// 公共方法:获取所有者信息
pub fn get_owner(&self) -> &str {
&self.owner
}
}
// 2. 继承与多态(Inheritance & Polymorphism):使用特质(trait)实现
// 定义一个特质(类似接口)
pub trait Shape {
fn area(&self) -> f64;
fn perimeter(&self) -> f64;
fn name(&self) -> &str;
}
// 实现特质的结构体:圆形
pub struct Circle {
radius: f64,
}
impl Circle {
pub fn new(radius: f64) -> Result<Self, String> {
if radius <= 0.0 {
return Err("半径必须为正数".to_string());
}
Ok(Circle { radius })
}
}
// 为Circle实现Shape特质
impl Shape for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
fn perimeter(&self) -> f64 {
2.0 * std::f64::consts::PI * self.radius
}
fn name(&self) -> &str {
"圆形"
}
}
// 实现特质的结构体:矩形
pub struct Rectangle {
width: f64,
height: f64,
}
impl Rectangle {
pub fn new(width: f64, height: f64) -> Result<Self, String> {
if width <= 0.0 || height <= 0.0 {
return Err("宽和高必须为正数".to_string());
}
Ok(Rectangle { width, height })
}
// 矩形特有的方法
pub fn is_square(&self) -> bool {
self.width == self.height
}
}
// 为Rectangle实现Shape特质
impl Shape for Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}
fn name(&self) -> &str {
if self.is_square() {
"正方形"
} else {
"矩形"
}
}
}
// 3. 动态多态:使用特质对象
// 处理任意形状的函数(多态行为)
pub fn print_shape_info(shape: &dyn Shape) {
println!("形状: {}", shape.name());
println!("面积: {:.2}", shape.area());
println!("周长: {:.2}", shape.perimeter());
println!("---");
}
// 4. 组合(Composition):Rust推荐使用组合而非继承
// 定义一个包含其他对象的结构体
pub struct Drawing {
name: String,
shapes: Vec<Box<dyn Shape>>, // 可以存储任意实现了Shape特质的对象
}
impl Drawing {
pub fn new(name: String) -> Self {
Drawing {
name,
shapes: Vec::new(),
}
}
// 添加形状到绘图中
pub fn add_shape(&mut self, shape: Box<dyn Shape>) {
self.shapes.push(shape);
}
// 计算绘图中所有形状的总面积
pub fn total_area(&self) -> f64 {
self.shapes.iter().map(|s| s.area()).sum()
}
// 显示绘图中所有形状的信息
pub fn display_all_shapes(&self) {
println!("绘图: {}", self.name);
println!("包含 {} 个形状", self.shapes.len());
println!("总面积: {:.2}", self.total_area());
println!("-----");
for shape in &self.shapes {
print_shape_info(shape);
}
}
}
fn main() {
// 演示封装
let mut account = BankAccount::new("123456789".to_string(), "张三".to_string());
if let Err(e) = account.deposit(1000.0) {
println!("存款失败: {}", e);
}
if let Err(e) = account.withdraw(300.0) {
println!("取款失败: {}", e);
}
println!("账户所有者: {}", account.get_owner());
println!("账户余额: {}\n", account.get_balance());
// 演示多态
let circle = Circle::new(5.0).unwrap();
let rectangle = Rectangle::new(4.0, 6.0).unwrap();
let square = Rectangle::new(3.0, 3.0).unwrap();
println!("=== 单个形状信息 ===");
print_shape_info(&circle);
print_shape_info(&rectangle);
print_shape_info(&square);
// 演示组合
let mut drawing = Drawing::new("我的绘图".to_string());
drawing.add_shape(Box::new(circle));
drawing.add_shape(Box::new(rectangle));
drawing.add_shape(Box::new(square));
println!("\n=== 绘图信息 ===");
drawing.display_all_shapes();
}
Rust 面向对象与传统 OOP 的区别
- 没有类(class) :Rust 使用结构体和枚举代替类
- 没有传统继承:通过特质实现行为共享,而非类继承
- 多态实现方式:使用特质对象实现动态多态,而非继承层次
- 更强调组合:Rust 鼓励 "组合优于继承" 的设计原则
- 严格的访问控制 :通过
pub
关键字精确控制可见性,没有 protected 级别