RUST入门(三)


前言

上一章中, 了解了RUST的安全, 这一章介绍下RUST的面向对象和函数式编程.


一、面向对象

1. RUST的"类"

RUST没有类, 最接近类的概念就是: 结构体

1.用struct来定义, 属性都以”,”结尾
2.结构体和属性默认都是private, “pub”表示公有
3.struct内不能创建函数

/// 结构体:订单.
///
/// # Examples
///
/// ```
/// let order = Order { order_no: String::from("123456") };
/// assert_eq!("123456", order.order_no);
/// ```
pub struct Order {
    pub order_no: String,

}

如果要创建函数, 需要使用impl关键字

用impl来对结构体添加函数 : 关联函数和静态函数
第一个是self参数, 或者&self参数的方法,称为关联函数
无self/&self参数, 可以理解为是静态函数

use bigdecimal::{BigDecimal, num_traits};
use std::str::FromStr;
use num_traits::Zero;

impl Order {
    ///
    /// 第一个是self参数, 或者&self参数的方法,称为关联函数
    /// self: 拥有self的所有权
    /// &self: 只有引用,无self的所有权
    /// 调用时先创建对象,再使用".",
    ///  # Examples
    /// ```
    /// let order = Order { order_no: String::from("123456") };
    /// let price = order.get_price();
    /// ```
    ///
    pub fn get_price(self)->BigDecimal{
        BigDecimal::from_str("10.00000001").unwrap_or(BigDecimal::zero())
    }
    ///
    /// 无self/&self参数, 可以理解为是静态函数
    /// 调用时无需创建对象,使用"::", 例如: Order::new(XX)
    ///
    pub fn new(order_no: String) -> Self {
        Self { order_no }
    }
}

2.面向对象特性-封装

封装是将基本的数据类型复合成一个自定义的类型, 并隐藏实现的细节
RUST利用结构体实现了封装. 示例: constructor, getter, setter

pub struct User{
    // name和age默认是私有的, 无法访问
    name:String,
    age:u32,
}
impl User{
    // 构造函数
    pub fn new(name: String, age: u32) -> Self {
        Self { name, age }
    }
    // getter
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn age(&self) -> u32 {
        self.age
    }
    // setter
    pub fn set_name(&mut self, name: String) {
        self.name = name;
    }
    pub fn set_age(&mut self, age: u32) {
        self.age = age;
    }
}

3.面向对象特性-继承

继承可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法

RUST不支持继承, 原因:

近年来继承作为一种语言设计的解决方案在很多语言中失宠了,因为其时常带有共享多于所需的代码的风险。
子类不应总是共享其父类的所有特征,但是继承却始终如此。
如此会使程序设计更为不灵活,并引入无意义的子类方法调用,或由于方法实际并不适用于子类而造成错误的可能性。

虽然没有传统意义上类的继承, 但是RUST支持trait的"继承", trait在下面的"多态"中会介绍
例如: Fn"继承"了FnMut
在这里插入图片描述
在这里插入图片描述

4.面向对象特性-多态

多态是同一个行为具有多个不同表现形式或形态的能力。
例如, java中的接口, 方法重载

RUST利用trait来实现多态
可以把trait理解为接口或者抽象类

RUST用trait来定义通用的行为

// 定义了2个空结构体
pub struct Dog;
pub struct Cat;

pub trait Animal {
  fn eat(&self); // 定义了行为,未实现. 有&self, 是关联函数
  fn drink() { // 定义了行为且有默认实现. 无self, 是静态函数
        println!("喝水")
    }
}

// 为狗和猫实现了Animal特性
impl Animal for Dog {
    fn eat(&self) {
        println!("狗吃饭")
    }
}

impl Animal for Cat {
    fn eat(&self) {
        println!("猫吃饭")
    }
}

// #[cfg(test)]是测试的宏
#[cfg(test)]
mod tests {
    use crate::animal::{Animal, Cat, Dog};

    #[test]
    fn it_works() {
        let cat = Cat {};
        let dog = Dog {};
        // 关联函数, 新建对象后, 用"."来调用
        cat.eat();
        // 静态函数, 直接"结构体::方法"来调用
        Cat::drink();

		// 关联函数, 新建对象后, 用"."来调用
        dog.eat();
        // 静态函数, 直接"结构体::方法"来调用
        Dog::drink();
    }
}

在这里插入图片描述


二、函数式编程

1. 闭包

RUST的闭包是指匿名函数, 可以保存在一个变量中, 或作为参数传递给其他函数

闭包作为变量:

// 闭包, 作为变量
let add = |a: usize, b: usize| { a + b };
let value = add(1, 2);
println!({}, value); // 打印出3

闭包作为参数:

// 闭包, 作为参数
let a = 3;
let b = 4;
// 把闭包作为了do_something函数的参数
// 注意, 闭包的作用域, 不同于自定义函数, 它可以把局部变量a和b也纳入作用域, 
let value = do_something(|| {
    // 此处即代码"return a+b;"
    a + b
});
println!({}, value); // 打印出7
fn do_something<F>(f: F) -> i32
    where F: Fn() -> i32
{
    // 执行函数f, 并返回i32.
    // 此处即代码"return fn();"
    f()
}

2. 迭代器

迭代器实现了Iterator trait, 例如: RUST的列表 Vec<?>

迭代器,作为一个高级的抽象,被编译成了与手写的底层代码大体一致性能代码。迭代器是 Rust 的 零成本抽象(zero-cost abstractions)之一,它意味着抽象并不会引入运行时开销。推荐优先使用迭代器的lambda语法

// vec!是用于创建列表的宏, 创建了包含1,2,3的列表
let v1 = vec![1, 2, 3];
let v2: Vec<i32> = v1.iter() //创建迭代器
    .zip(vec![1, 1, 1]) //zip翻译为拉链, 把2侧的数据做组合, 形成元组[(1,1),(2,1),(3,1)]
       .map(|(a, b)| { a + b }) //元组内部相加[2,3,4]
       .filter(|x| *x > 2) // 过滤出大于2的[3,4]
       .collect();
// 打印出3,4
for x in v2 {
    println!("{}", x);
}

总结

本章介绍了RUST的面向对象和函数式编程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值