前言
在上一章中, 了解了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的面向对象和函数式编程