Rust语法之面向对象编程

Rust 虽然不是纯粹的面向对象编程语言,但它通过结构体(struct)、枚举(enum)、特质(trait)等特性支持面向对象编程(OOP)的核心概念,如封装、继承和多态。以下是 Rust 面向对象编程的完整实现与说明:

代码说明

1. 封装(Encapsulation)

  • 实现方式:通过结构体的私有字段和公共方法实现

  • 示例解析

    • BankAccount 结构体的字段(account_numberbalanceowner)都是私有的,无法直接访问
    • 提供公共方法(depositwithdrawget_balance 等)来操作和访问这些字段
    • 方法内部可以进行数据验证(如确保存款金额为正数),保证数据完整性

2. 继承与多态(通过特质实现)

  • 特质(Trait) :类似其他语言的接口,定义了一组方法签名

    • Shape 特质定义了所有形状都应具备的方法(areaperimetername
  • 多态实现

    • 不同结构体(CircleRectangle)可以实现同一个特质
    • 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 的区别

  1. 没有类(class) :Rust 使用结构体和枚举代替类
  2. 没有传统继承:通过特质实现行为共享,而非类继承
  3. 多态实现方式:使用特质对象实现动态多态,而非继承层次
  4. 更强调组合:Rust 鼓励 "组合优于继承" 的设计原则
  5. 严格的访问控制 :通过 pub 关键字精确控制可见性,没有 protected 级别
相关推荐
brzhang6 小时前
Google 浏览器出了一个超级好用的功能,Gemini 原生支持,帮你解决性能问题
前端·后端·架构
洛卡卡了6 小时前
适配私有化部署,我手写了套支持离线验证的 License 授权系统
java·后端·架构
SimonKing6 小时前
亲测有效!分享一个稳定访问GitHub,快速下载资源的实用技巧
java·后端·程序员
这里有鱼汤6 小时前
量化小白必看|MiniQMT踩坑记:想做实盘这些知识请你一定要掌握
后端·python
TechLee6 小时前
Laravel 权限控制新选择:使用 Laravel-authz 集成 PHP-Casbin
后端·php
青梅主码6 小时前
量子位智库最新发布《 AI Coding 玩家图谱》: AI 编码玩家图谱全解析
后端
武子康6 小时前
大数据-85 Spark Action 操作详解:从 Collect 到存储的全景解析
大数据·后端·spark
唐天一6 小时前
Rust 基础之常用语法
后端
绝无仅有6 小时前
Go 语言面试之通道 (Channel) 解密
后端·面试·github