提示
所有帖子都会不定期添加补充实战过程中发现的新内容,力争一篇文章涵盖所有内容,避免你多次查找文章,所以最好点赞或收藏,时不时回来看看。
废话
面向对象使代码得到复用,但要求有良好的OOP思维,面向对象有三个特点,封装、继承、多态,在rust里结构体可以当类使用,实现了封装,多态可以纯手写或者定义好Trait组合使用(rust提倡组合优于继承),继承在rust里没有明确的实现方式,经过一翻探索,发现使用Deref解引用来实现相对最好,当然也可以使用AsRef实现显示的类型转换(算是类型强制转换的写法吧)如果你发现更好的,一定记得告诉我。
一段漂亮的代码
use std::ops::Deref;
use std::ops::DerefMut;
// 封装父类或叫基类
struct Control {
x: u32,
y: u32,
}
// 基类的实现
impl Control {
fn paint(&self) {
println!("control x:{}, y:{}", self.x, self.y);
}
}
// 封装子类
struct Button {
control: Control,
text: String,
}
// 子类的实现
impl Button {
// 这里的paint是模拟多态,严格来说并不是多态,如果定义包含paint的Trait供父类和子类实现才可以说是严格意义上的多态
fn paint(&self) {
println!("button x:{}, y:{}, text:{}", self.control.x, self.control.y, self.text);
}
}
// 不可变解引用实现
impl Deref for Button {
type Target = Control; // 不可变解引用的目标是Control
fn deref<'a>(&'a self) -> &'a Control {
&self.control
}
}
// 可变解引用实现
impl DerefMut for Button {
//type Target = Control; 可变解引用不需要写目标
fn deref_mut<'a>(&'a mut self) -> &'a mut Control {
&mut self.control
}
}
/// 显示类型转换
impl AsRef<Control> for Button {
fn as_ref(&self) -> &Control {
&self.control
}
}
fn main() {
// 定义子类对象
let mut button = Button {
control: Control {
x: 10,
y: 12,
},
text: "确定".to_string(),
};
{ // 当父类对象使用,配对的{}限制了可变借用的范围,不是必需要写,是编程的严谨性
let mut control: &mut Control = &mut button;
control.x = 20;
control.y = 22;
control.paint(); // 调用父类的方法,有点super或base的味道了
}
button.paint(); // 调用子类自己的方法
button.as_ref().paint(); // 显式转换为control类型
}
执行结果:
control x:20, y:22
button x:20, y:22, text:确定
control x:20, y:22
在面向对象开发里的类,往往包含字段和方法,如果说你的类里方法很少甚至没有,那么也可以用下面的方式来处理,我是
参考了这篇文章
// 水果特性
trait FruitTrait {
fn get_type(&self);
}
// 苹果
struct Apple { }
impl FruitTrait for Apple {
fn get_type(&self) {
println!("I'm Apple");
}
}
// 桔子
struct Orange { }
impl FruitTrait for Orange {
fn get_type(&self) {
println!("I'm Orange");
}
}
struct FruitFactory1 {
subclass: Box<FruitTrait>,
}
impl FruitTrait for FruitFactory1 {
fn get_type(&self) {
self.subclass.get_type();
}
}
struct FruitFactory2<T: FruitTrait> {
subclass: T
}
impl<T: FruitTrait> FruitTrait for FruitFactory2<T> {
fn get_type(&self) {
self.subclass.get_type();
}
}
pub type OrangeFactory = FruitFactory2<Orange>;
fn main() {
let apple = FruitFactory1 {
subclass: Box::new(Apple{}),
};
apple.subclass.get_type();
let orange = OrangeFactory {
subclass: Orange{},
};
orange.subclass.get_type();
}
FruitFactory1和FruitFactory2这两种方案又各有优缺点。
第一种对外来说是一个单独的类型Fruit,这既是优点也是缺点:它的大小是固定的,可以方便的放在Vec里面。外界想要知道具体类型信息的话,可以通过提供一个get_type() 之类的办法来提供。
第二种方案对外来说是一组类型你可以使用不同的impl 规则来为它们添加方法。然后你可以用类似于
pub type OrangeFactory = FruitFactory2;
把类型暴露给其他组件使用,是不是类似C++/Java 中继承设计的方案。