陈天 · Rust 编程第一课
陈天
Tubi TV 研发副总裁
23195 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 65 讲
基础篇 (21讲)
陈天 · Rust 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

25|类型系统:如何围绕trait来设计和架构系统?

Yew 库中的 trait 定义
用 trait 实现 SOLID 原则
用于 SQL 方言解析
使用 trait 提供控制反转
桥接 thumbor 代码和 photon crate
在软件开发中的应用
好用、易用
使用体验
SpecTransform vs. ImageTransform
延迟图片类型判断和支持的决策
传入的 image 类型不同的问题
第一版的 trait 设计
统一处理任意类型的图片 spec
围绕 trait 来设计和架构系统
类似钢筋、砖瓦、螺丝、钉子、插座等标准组件
Rust 语言标准库中的标准 trait
不断创建和迭代接口
思考题
SOLID 原则
Dialect trait
控制反转
Engine trait
桥接
接口设计关注点
Trait 设计取舍
泛型 trait
设计取舍
ImageTransform trait
SpecTransform trait
接口设计和架构系统
相关接口
标准化接口
软件开发行为
Trait 设计和架构系统
类型系统设计和架构系统

该思维导图由 AI 生成,仅供参考

你好,我是陈天。
Trait,trait,trait,怎么又是 trait?how old are you?
希望你还没有厌倦我们没完没了地聊关于 trait 的话题。因为 trait 在 Rust 开发中的地位,怎么吹都不为过。
其实不光是 Rust 中的 trait,任何一门语言,和接口处理相关的概念,都是那门语言在使用过程中最重要的概念。软件开发的整个行为,基本上可以说是不断创建和迭代接口,然后在这些接口上进行实现的过程
在这个过程中,有些接口是标准化的,雷打不动,就像钢筋、砖瓦、螺丝、钉子、插座等这些材料一样,无论要构筑的房子是什么样子的,这些标准组件的接口在确定下来后,都不会改变,它们就像 Rust 语言标准库中的标准 trait 一样。
而有些接口是跟构造的房子息息相关的,比如门窗、电器、家具等,它们就像你要设计的系统中的 trait 一样,可以把系统的各个部分联结起来,最终呈现给用户一个完整的使用体验。
之前讲了 trait 的基础知识,也介绍了如何在实战中使用 trait 和 trait object。今天,我们再花一讲的时间,来看看如何围绕着 trait 来设计和架构系统。
由于在讲架构和设计时,不免要引入需求,然后我需要解释这需求的来龙去脉,再提供设计思路,再介绍 trait 在其中的作用,但这样下来,一堂课的内容能讲好一个系统设计就不错了。所以我们换个方式,把之前设计过的系统捋一下,重温它们的 trait 设计,看看其中的思路以及取舍。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了如何使用trait来设计和架构系统,强调了良好的接口设计对系统的重要性。通过具体的代码示例和思考,阐述了如何围绕trait来设计和架构系统,以及如何通过trait让代码更加自然舒服好用。文章重点讨论了trait在Rust开发中的重要性,并指出任何一门语言中,接口处理相关的概念都是最重要的。此外,还介绍了如何使用trait进行控制反转,以及如何通过trait提供桥接功能。通过trait的灵活性,可以让调用者和被调用者只需要关心它们之间的接口,而非具体的数据结构。作者还强调了面向对象设计时SOLID原则中的重要性,以及如何在Rust中践行这些原则。总的来说,本文通过具体的代码示例和思考,深入浅出地介绍了如何围绕trait来设计和架构系统,强调了良好的接口设计对系统的重要性。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(8)

  • 最新
  • 精选
  • 郑晔
    老师对单一职责的理解是错的,这一点是我特意在《软件设计之美》中纠正的,因为单一功能是一个永远为真的说法,单一职责是要把变化纳入考量。具体的可以参考《软件设计之美》和《架构整洁之道》中关于单一职责的讲解。

    作者回复: 谢谢指正。我的理解来自于 https://en.wikipedia.org/wiki/Single-responsibility_principle > 一个类或模块应该有一个,而且只有一个,改变(例如重写)的理由

    2021-10-30
    3
    5
  • Marvichov
    doc: https://github.com/yewstack/yew/blob/master/packages/yew/src/html/component/mod.rs#L42 1. 不能, 返回类型有Self; 运行时type被erase掉了, 不知道Self具体是什么类型. 2. Message感觉有点像actor里面的message: op to change component state. 应该是用于定义交互的时候, dynamic change component的. Properties应该是DOM的property, 用于render view的… 比如impl Component for List https://github.com/yewstack/yew/blob/master/packages/yew/src/virtual_dom/vlist.rs#L495 ``` #[derive(Clone, Properties, PartialEq)] pub struct ListProps { pub children: Children, } impl Component for List { fn view(&self, ctx: &Context<Self>) -> Html { html! { <>{ for ctx.props().children.iter() }</> } } ``` 3. https://docs.rs/yew/0.18.0/yew/#example; 重点是`Sized` `+ 'Static` bound`. 实现的类型必须是Sized. 同时如果有reference element, 其lifetime必须是static的. 感觉virtual dom有必要了解了解...

    作者回复: 👍 非常好!

    2021-10-23
    2
    1
  • 核桃
    今天写了一段全局单例的代码,如下所示. ``` pub struct Monitor { sender: UnsafeCell<Option<mpsc::TxUnbounded<Vec<xxx>>>>, } impl Monitor { pub fn set_sender(&self, sender: mpsc::TxUnbounded<Vec<xxx>>) { let self_sender_option: &mut Option<mpsc::TxUnbounded<Vec<xxx>>> = unsafe { transmute(self.sender.get()) }; self_sender_option.replace(sender); } pub fn send_monitor(&self, info_vec: Vec<xxx>) { let self_sender: &mut Option<mpsc::TxUnbounded<Vec<xxx>>> = unsafe { transmute(self.sender.get()) }; ... } } unsafe impl Send for Monitor {} unsafe impl Sync for Monitor {} //why we use Arc to contain Monitor is that lazy_static seems a const value. //rust can't change the const value unless new at first. //but Arc can share to use the value. lazy_static! { pub static ref GLOBAL_MONITOR: Arc<Monitor> = Arc::new(Monitor { sender: UnsafeCell::new(None) }); } ``` 这里使用lazy_static进行全局实现静态变量,但是因为初始化的时候并没有办法指向一个其他的变量,因此这里考虑使用了Arc处理,但是这段代码其实还是有点问题的,因为并没有考虑到竞争并发的情况,但是这里似乎更加适合使用once cell。rust在这部分的实现,感觉还是有点欠缺的。

    作者回复: 👍

    2021-11-25
    2
  • 0@1
    老师,想问下关于trait的一些问题, 下面是个代码例子, struct MyStruct; trait MyTrait{ fn test(&self); } impl MyTrait for MyStruct{ fn test(&self) { println!("MyStruct") } } impl MyTrait for &MyStruct{ fn test(&self) { println!("&MyStruct") } } impl MyTrait for *const MyStruct{ fn test(&self) { println!("*const MyStruct") } } fn main() { let my_struct = MyStruct; my_struct.test(); &my_struct.test(); let my_struct_ptr = &my_struct as *const MyStruct; my_struct_ptr.test(); } 1. impl MyTrait for &MyStruct 和 impl MyTrait for MyStruct 这2个有什么区别,什么情况下适合 为引用实现trait, impl MyTrait for &MyStruct 2. impl MyTrait for *const MyStruct 这种方式,给裸指针实现trait, 有什么使用场景么

    作者回复: trait 就是让对应的类型拥有对应的行为。所以你为 struct 实现 trait,这个 struct 类型就有了 trait 的行为;你对 struct 的引用实现 trait,struct 类型的引用就有了 trait 的行为;裸指针也是类似。当你持有一个 *const MyStruct 的数据时,你可以调用 trait 的方法。对裸指针来说,一般实现 trait 的意义不大,因为 self 此时可干的事情很少。

    2021-10-23
  • 罗杰
    接口的设计要注重用户体验,这太重要了。

    作者回复: 👍

    2021-10-22
  • David.Du
    Trait 对T的一些约束,同时也提醒了T的实现者,要按照这个去做,Fn的函数功能,同时也约束了自身,我感觉一套系统定义完一些列的Trait+数据结构后,剩下的就是实现了。
    2023-11-06归属地:河南
  • 进击的Lancelot
    思考题: Component trait 可以做 trait object 么? 做不了 trait object,因为其中的方法并不符合对象安全原则,要么返回 Self 对象,要么带有泛型参数 关联类型 Message 和 Properties 的作用是什么? Message 的作用是用来和 Component 进行交互,使其获得动态能力的。 properties 则表达了 Component 的属性,当 Component 的父组件被重新渲染时,子组件要么重新生成,要么从传递给 changed 方法中的上下文接受新的 properties 做为使用者,该如何用 Component trait?它的 lifecycle 是什么样子的? 为自定义类型实现 Component trait 需要指定关联类型 Message 和 Properties,并提供 create 和 view 两个方法的自定义实现即可。它的 lifecycle 是静态生命周期,贯穿程序的始终
    2022-09-16归属地:广东
  • 渡鸦10086
    思考题: 1. Component trait 的 create 方法会返回 Self,所以不能做 trait Object 2. 关联类型 Message 用于让 Components 类型动态化及可交互化,Component 可以使用 enum 或 () 来声明。 Properties 就是 Component 的属性,当 Component 的父组件被重新渲染时时,它将被重新创建,或者在传递给被改变的 life cycle 方法的上下文中接收新的属性。 3. YEW的官方实例:https://docs.rs/yew/0.18.0/yew/#example。life cycle : `'static` 代表静态生命周期 4. 没有前端经验。。
    2022-01-17
收起评论
显示
设置
留言
8
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部