【Rust】——面向对象设计模式的实现
🎼个人主页:【Y小夜】
😎作者简介:一位双非学校的大二学生,编程爱好者,
专注于基础和实战分享,欢迎私信咨询!
🎆入门专栏:🎇【MySQL,Java基础,Rust】
🎈热门专栏:🎊【Python,Javaweb,Vue框架】
感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️

学习推荐:
人工智能是一个涉及数学、计算机科学、数据科学、机器学习、神经网络等多个领域的交叉学科,其学习曲线相对陡峭,对初学者来说可能会有一定的挑战性。幸运的是,随着互联网教育资源的丰富,现在有大量优秀的在线平台和网站提供了丰富的人工智能学习材料,包括视频教程、互动课程、实战项目等,这些资源无疑为学习者打开了一扇通往人工智能世界的大门。
前些天发现了一个巨牛的人工智能学习网站:前言 – 人工智能教程通俗易懂,风趣幽默,忍不住分享一下给大家。
目录
🎯定义Post并新建一个草案状态的实例
🎯存放博文内容的文本
🎯确保博文草案的内容是空的
🎯请求审核博文来改变其状态
🎯增加改变content行为的approve方法
🎯状态模式的权衡取舍
🎯将状态和行为编码为类型
🎯实现状态转移为不同类型的转换
状态模式(state pattern)是一个面向对象设计模式。该模式的关键在于定义一系列值的内含状态。这些状态体现为一系列的 状态对象,同时值的行为随着其内部状态而改变。我们将编写一个博客发布结构体的例子,它拥有一个包含其状态的字段,这是一个有着 "draft"、"review" 或 "published" 的状态对象
状态对象共享功能:当然,在 Rust 中使用结构体和 trait 而不是对象和继承。每一个状态对象负责其自身的行为,以及该状态何时应当转移至另一个状态。持有一个状态对象的值对于不同状态的行为以及何时状态转移毫不知情。
使用状态模式的优点在于,程序的业务需求改变时,无需改变值持有状态或者使用值的代码。我们只需更新某个状态对象中的代码来改变其规则,或者是增加更多的状态对象。
首先我们将以一种更加传统的面向对象的方式实现状态模式,接着使用一种更 Rust 一点的方式。让我们使用状态模式增量式地实现一个发布博文的工作流以探索这个概念。
这个博客的最终功能看起来像这样:
- 博文从空白的草案开始。
- 一旦草案完成,请求审核博文。
- 一旦博文过审,它将被发表。
- 只有被发表的博文的内容会被打印,这样就不会意外打印出没有被审核的博文的文本。
任何其他对博文的修改尝试都是没有作用的。例如,如果尝试在请求审核之前通过一个草案博文,博文应该保持未发布的状态。
这是一个我们将要在一个叫做
blog的库 crate 中实现的 API 的示例。这段代码还不能编译,因为还未实现blog。use blog::Post;fn main() {let mut post = Post::new();post.add_text("I ate a salad for lunch today");assert_eq!("", post.content());post.request_review();assert_eq!("", post.content());post.approve();assert_eq!("I ate a salad for lunch today", post.content()); }我们希望允许用户使用
Post::new创建一个新的博文草案。也希望能在草案阶段为博文编写一些文本。如果在审批之前尝试立刻获取博文的内容,不应该获取到任何文本因为博文仍然是草案。一个好的单元测试将是断言草案博文的content方法返回空字符串,不过我们并不准备为这个例子编写单元测试。接下来,我们希望能够请求审核博文,而在等待审核的阶段
content应该仍然返回空字符串。最后当博文审核通过,它应该被发表,这意味着当调用content时博文的文本将被返回。注意我们与 crate 交互的唯一的类型是
Post。这个类型会使用状态模式并会存放处于三种博文所可能的状态之一的值 —— 草案,等待审核和发布。状态上的改变由Post类型内部进行管理。状态依库用户对Post实例调用的方法而改变,但是不能直接管理状态变化。这也意味着用户不会在状态上犯错,比如在过审前发布博文。
🎯定义Post并新建一个草案状态的实例
让我们开始实现这个库吧!我们知道需要一个公有
Post结构体来存放一些文本,所以让我们从结构体的定义和一个创建Post实例的公有关联函数new开始,
Post将在私有字段state中存放一个Option<T>类型的 trait 对象Box<dyn State>。稍后将会看到为何Option<T>是必须的。pub struct Post {state: Option<Box<dyn State>>,content: String, }impl Post {pub fn new() -> Post {Post {state: Some(Box::new(Draft {})),content: String::new(),}} }trait State {}struct Draft {}impl State for Draft {}
Statetrait 定义了所有不同状态的博文所共享的行为,这个状态对象是Draft、PendingReview和Published,它们都会实现State状态。现在这个 trait 并没有任何方法,同时开始将只定义Draft状态因为这是我们希望博文的初始状态。当创建新的
Post时,我们将其state字段设置为一个存放了Box的Some值。这个Box指向一个Draft结构体新实例。这确保了无论何时新建一个Post实例,它都会从草案开始。因为Post的state字段是私有的,也就无法创建任何其他状态的Post了!。Post::new函数中将content设置为新建的空String。
🎯存放博文内容的文本
展示了我们希望能够调用一个叫做
add_text的方法并向其传递一个&str来将文本增加到博文的内容中。选择实现为一个方法而不是将content字段暴露为pub。这意味着之后可以实现一个方法来控制content字段如何被读取。impl Post {// --snip--pub fn add_text(&mut self, text: &str) {self.content.push_str(text);} }
add_text获取一个self的可变引用,因为需要改变调用add_text的Post实例。接着调用content中的String的push_str并传递text参数来保存到content中。这不是状态模式的一部分,因为它的行为并不依赖博文所处的状态。add_text方法完全不与state状态交互,不过这是我们希望支持的行为的一部分。
🎯确保博文草案的内容是空的
即使调用
add_text并向博文增加一些内容之后,我们仍然希望content方法返回一个空字符串 slice,因为博文仍然处于草案状态,如示例 17-11 的第 8 行所示。现在让我们使用能满足要求的最简单的方式来实现content方法:总是返回一个空字符串 slice。当实现了将博文状态改为发布的能力之后将改变这一做法。但是目前博文只能是草案状态,这意味着其内容应该总是空的。impl Post {// --snip--pub fn content(&self) -> &str {""} }
🎯请求审核博文来改变其状态
接下来需要增加请求审核博文的功能,这应当将其状态由
Draft改为PendingReview。impl Post {// --snip--pub fn request_review(&mut self) {if let Some(s) = self.state.take() {self.state = Some(s.request_review())}} }trait State {fn request_review(self: Box<Self>) -> Box<dyn State>; }struct Draft {}impl State for Draft {fn request_review(self: Box<Self>) -> Box<dyn State> {Box::new(PendingReview {})} }struct PendingReview {}impl State for PendingReview {fn request_review(self: Box<Self>) -> Box<dyn State> {self} }这里为
Post增加一个获取self可变引用的公有方法request_review。接着在Post的当前状态下调用内部的request_review方法,并且第二个request_review方法会消费当前的状态并返回一个新状态。这里给
Statetrait 增加了request_review方法;所有实现了这个 trait 的类型现在都需要实现request_review方法。注意不同于使用self、&self或者&mut self作为方法的第一个参数,这里使用了self: Box<Self>。这个语法意味着该方法只可在持有这个类型的Box上被调用。这个语法获取了Box<Self>的所有权使老状态无效化,以便Post的状态值可转换为一个新状态。为了消费老状态,
request_review方法需要获取状态值的所有权。这就是Post的state字段中Option的来历:调用take方法将state字段中的Some值取出并留下一个None,因为 Rust 不允许结构体实例中存在值为空的字段。这使得我们将state的值移出Post而不是借用它。接着我们将博文的state值设置为这个操作的结果。我们需要将
state临时设置为None来获取state值,即老状态的所有权,而不是使用self.state = self.state.request_review();这样的代码直接更新状态值。这确保了当Post被转换为新状态后不能再使用老state值。
Draft的request_review方法需要返回一个新的,装箱的PendingReview结构体的实例,其用来代表博文处于等待审核状态。结构体PendingReview同样也实现了request_review方法,不过它不进行任何状态转换。相反它返回自身,因为当我们请求审核一个已经处于PendingReview状态的博文,它应该继续保持PendingReview状态。
🎯增加改变content行为的approve方法
approve方法将与request_review方法类似:它会将state设置为审核通过时应处于的状态impl Post {// --snip--pub fn approve(&mut self) {if let Some(s) = self.state.take() {self.state = Some(s.approve())}} }trait State {fn request_review(self: Box<Self>) -> Box<dyn State>;fn approve(self: Box<Self>) -> Box<dyn State>; }struct Draft {}impl State for Draft {// --snip--fn approve(self: Box<Self>) -> Box<dyn State> {self} }struct PendingReview {}impl State for PendingReview {// --snip--fn approve(self: Box<Self>) -> Box<dyn State> {Box::new(Published {})} }struct Published {}impl State for Published {fn request_review(self: Box<Self>) -> Box<dyn State> {self}fn approve(self: Box<Self>) -> Box<dyn State> {self} }这里为
Statetrait 增加了approve方法,并新增了一个实现了State的结构体,Published状态。类似于
PendingReview中request_review的工作方式,如果对Draft调用approve方法,并没有任何效果,因为它会返回self。当对PendingReview调用approve时,它返回一个新的、装箱的Published结构体的实例。Published结构体实现了Statetrait,同时对于request_review和approve两方法来说,它返回自身,因为在这两种情况博文应该保持Published状态。impl Post {// --snip--pub fn content(&self) -> &str {self.state.as_ref().unwrap().content(self)}// --snip-- }因为目标是将所有像这样的规则保持在实现了
State的结构体中,我们将调用state中的值的content方法并传递博文实例(也就是self)作为参数。接着返回state值的content方法的返回值。这里调用
Option的as_ref方法是因为需要Option中值的引用而不是获取其所有权。因为state是一个Option<Box<dyn State>>,调用as_ref会返回一个Option<&Box<dyn State>>。如果不调用as_ref,将会得到一个错误,因为不能将state移动出借用的&self函数参数。接着我们就有了一个
&Box<dyn State>,当调用其content时,Deref 强制转换会作用于&和Box,这样最终会调用实现了Statetrait 的类型的content方法。trait State {// --snip--fn content<'a>(&self, post: &'a Post) -> &'a str {""} }// --snip-- struct Published {}impl State for Published {// --snip--fn content<'a>(&self, post: &'a Post) -> &'a str {&post.content} }这里增加了一个
content方法的默认实现来返回一个空字符串 slice。这意味着无需为Draft和PendingReview结构体实现content了。Published结构体会覆盖content方法并会返回post.content的值。
🎯状态模式的权衡取舍
我们展示了 Rust 是能够实现面向对象的状态模式的,以便能根据博文所处的状态来封装不同类型的行为。
Post的方法并不知道这些不同类型的行为。通过这种组织代码的方式,要找到所有已发布博文的不同行为只需查看一处代码:Published的Statetrait 的实现。如果要创建一个不使用状态模式的替代实现,则可能会在
Post的方法中,或者甚至于在main代码中用到match语句,来检查博文状态并在这里改变其行为。这意味着需要查看很多位置来理解处于发布状态的博文的所有逻辑!这在增加更多状态时会变得更糟:每一个match语句都会需要另一个分支。对于状态模式来说,
Post的方法和使用Post的位置无需match语句,同时增加新状态只涉及到增加一个新struct和为其实现 trait 的方法。这个实现易于扩展增加更多功能。为了体会使用此模式维护代码的简洁性,请尝试如下一些建议:
- 增加
reject方法将博文的状态从PendingReview变回Draft- 在将状态变为
Published之前需要两次approve调用- 只允许博文处于
Draft状态时增加文本内容。提示:让状态对象负责内容可能发生什么改变,但不负责修改Post。状态模式的一个缺点是因为状态实现了状态之间的转换,一些状态会相互联系。如果在
PendingReview和Published之间增加另一个状态,比如Scheduled,则不得不修改PendingReview中的代码来转移到Scheduled。如果PendingReview无需因为新增的状态而改变就更好了,不过这意味着切换到另一种设计模式。另一个缺点是我们会发现一些重复的逻辑。为了消除它们,可以尝试为
Statetrait 中返回self的request_review和approve方法增加默认实现,不过这会违反对象安全性,因为 trait 不知道self具体是什么。我们希望能够将State作为一个 trait 对象,所以需要其方法是对象安全的。另一个重复是
Post中request_review和approve这两个类似的实现。它们都委托调用了state字段中Option值的同一方法,并在结果中为state字段设置了新值。如果Post中的很多方法都遵循这个模式,我们可能会考虑定义一个宏来消除重复(查看第十九章的 “宏” 部分)。完全按照面向对象语言的定义实现这个模式并没有尽可能地利用 Rust 的优势。让我们看看一些代码中可以做出的修改,来将无效的状态和状态转移变为编译时错误。
🎯将状态和行为编码为类型
我们将展示如何稍微反思状态模式来进行一系列不同的权衡取舍。不同于完全封装状态和状态转移使得外部代码对其毫不知情,我们将状态编码进不同的类型。如此,Rust 的类型检查就会将任何在只能使用发布博文的地方使用草案博文的尝试变为编译时错误。
fn main() {let mut post = Post::new();post.add_text("I ate a salad for lunch today");assert_eq!("", post.content()); }我们仍然希望能够使用
Post::new创建一个新的草案博文,并能够增加博文的内容。不过不同于存在一个草案博文时返回空字符串的content方法,我们将使草案博文完全没有content方法。这样如果尝试获取草案博文的内容,将会得到一个方法不存在的编译错误。这使得我们不可能在生产环境意外显示出草案博文的内容,因为这样的代码甚至就不能编译。pub struct Post {content: String, }pub struct DraftPost {content: String, }impl Post {pub fn new() -> DraftPost {DraftPost {content: String::new(),}}pub fn content(&self) -> &str {&self.content} }impl DraftPost {pub fn add_text(&mut self, text: &str) {self.content.push_str(text);} }
Post和DraftPost结构体都有一个私有的content字段来储存博文的文本。这些结构体不再有state字段因为我们将状态编码改为结构体类型。Post将代表发布的博文,它有一个返回content的content方法。仍然有一个
Post::new函数,不过不同于返回Post实例,它返回DraftPost的实例。现在不可能创建一个Post实例,因为content是私有的同时没有任何函数返回Post。
🎯实现状态转移为不同类型的转换
那么如何得到发布的博文呢?我们希望强制执行的规则是草案博文在可以发布之前必须被审核通过。等待审核状态的博文应该仍然不会显示任何内容。让我们通过增加另一个结构体
PendingReviewPost来实现这个限制,在DraftPost上定义request_review方法来返回PendingReviewPost,并在PendingReviewPost上定义approve方法来返回Postimpl DraftPost {// --snip--pub fn request_review(self) -> PendingReviewPost {PendingReviewPost {content: self.content,}} }pub struct PendingReviewPost {content: String, }impl PendingReviewPost {pub fn approve(self) -> Post {Post {content: self.content,}} }
request_review和approve方法获取self的所有权,因此会消费DraftPost和PendingReviewPost实例,并分别转换为PendingReviewPost和发布的Post。这样在调用request_review之后就不会遗留任何DraftPost实例,后者同理。PendingReviewPost并没有定义content方法,所以尝试读取其内容会导致编译错误,DraftPost同理。因为唯一得到定义了content方法的Post实例的途径是调用PendingReviewPost的approve方法,而得到PendingReviewPost的唯一办法是调用DraftPost的request_review方法,现在我们就将发博文的工作流编码进了类型系统。这也意味着不得不对
main做出一些小的修改。因为request_review和approve返回新实例而不是修改被调用的结构体,所以我们需要增加更多的let post =覆盖赋值来保存返回的实例。也不再能断言草案和等待审核的博文的内容为空字符串了,我们也不再需要它们:不能编译尝试使用这些状态下博文内容的代码。use blog::Post;fn main() {let mut post = Post::new();post.add_text("I ate a salad for lunch today");let post = post.request_review();let post = post.approve();assert_eq!("I ate a salad for lunch today", post.content()); }不得不修改
main来重新赋值post使得这个实现不再完全遵守面向对象的状态模式:状态间的转换不再完全封装在Post实现中。然而,得益于类型系统和编译时类型检查,我们得到了的是无效状态是不可能的!这确保了某些特定的 bug,比如显示未发布博文的内容,将在部署到生产环境之前被发现。
相关文章:
【Rust】——面向对象设计模式的实现
🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大二学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL࿰…...
C#朗读语音
最近有个需求,需要在C#程序发生异常时候,朗读文字,C#提供了.net framework可以提供简单的语音朗读功能。 引入依赖 using System.Media; using System.Speech.Synthesis; using System.Runtime.InteropServices; //报警音量 SystemSounds.…...
c++ 简单的日志类 CCLog
此日志类,简单地实现了向标准输出控制台和文件输出日志信息的功能,并能在这两者之间进行切换输出,满足输出日志的不同需求。 代码如下: /** CCLog.h* c_common_codes** Created by xichen on 12-1-12.* Copyright 2012 cc_te…...
一文读懂 Compose 支持 Accessibility 无障碍的原理
前言 众所周知,Compose 作为一种 UI 工具包,向开发者提供了实现 UI 的基本功能。但其实它还默默提供了很多其他能力,其中之一便是今天需要讨论的:Android 特色的 Accessibility 功能。 采用 Compose 搭建的界面,完美…...
Redis到底支不支持事务?
文章目录 一、概述二、使用1、正常执行:2、主动放弃事务3、全部回滚:4、部分支持事务:5、WATCH: 三、事务三阶段四、小结 redis是支持事务的,但是它与传统的关系型数据库中的事务是有所不同的 一、概述 概念: 可以一次执行多个命令,本质是一…...
美颜相机「BeautyCam」v12.0.80 祛广告解索会员版(美妆相机功能,展现女神魅力)
软件介绍 美颜相机,一款由知名移动互联网企业Meitu Inc.开发的移动设备照片编辑与美化应用,起初主要针对娱乐消费市场,随后集成了商业营销功能。目前,它已跻身全球最受欢迎的手机摄影应用程序之列。在中国,美颜相机和…...
Oracle的优化器
sql优化第一步:搞懂Oracle中的SQL的执行过程 从图中我们可以看出SQL语句在Oracle中经历了以下的几个步骤: 语法检查:检查SQL拼写是否正确,如果不正确,Oracle会报语法错误。 语义检查:检查SQL中的访问对象…...
[线程与网络] 网络编程与通信原理(六):深入理解应用层http与https协议(网络编程与通信原理完结)
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏:🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 🧀Java …...
个人博客的未来出路在哪里?
说起个人博客的未来这就是个悲伤的话题,估计不少个人博客站长们都在苦苦的坚持和挣扎着吧,反正明月这两年感受最深刻的就是又有不少个人博客站点停更和 404 了都。自从坚持写博客这近十来年这种情况也都见怪不怪了,但这两年最突出的就是很多站长都是迷茫和悲观。 明月去年在…...
【TensorFlow深度学习】实现Actor-Critic算法的关键步骤
实现Actor-Critic算法的关键步骤 实现Actor-Critic算法的关键步骤:强化学习中的双剑合璧Actor-Critic算法简介关键实现步骤代码示例(使用TensorFlow)结语 实现Actor-Critic算法的关键步骤:强化学习中的双剑合璧 在强化学习的广阔…...
微服务架构-可见可观测与量化分析体系
目录 一、可见可观测 1.1 概述 1.2 服务可见性 1.2.1 概述 1.2.2 服务描述 1.2.3 服务所有权 1.2.4 服务对外接口 1.2.5 服务SLA 1.2.6 服务的上下游拓扑 1.2.7 服务变更 1.2.8 服务接入和资源配额管理 1.2.9 服务线上部署和线下测试环境信息 1.3 变更可见性 1.4 …...
PostgreSQL的视图pg_indexes
PostgreSQL的视图pg_indexes 基础信息 OS版本:Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本:16.2 pg软件目录:/home/pg16/soft pg数据目录:/home/pg16/data 端口:5777pg_indexes 是 PostgreSQL 中的一…...
暂停系统更新
电脑左下角搜索注册表编辑器 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings 找到这个目录 打开FlightSettingsMaxPauseDays,没找到的话就创建一个同名文件夹然后选择10进制填入3550 最后进入系统暂停更新界面选择最下面…...
Python离线查询IP地址对应的国家和城市
使用场景: 在没网的情况下使用python代码实现对ip地址进行查询国家和地市 代码实现: 需要安装 pip install geoip2 库 import geoip2.databasedef get_location_by_ip(ip_address, db_path):reader geoip2.database.Reader(db_path)try:response r…...
使用Aspose技术将Excel/Word转换为PDF
简介:本文将介绍如何使用Aspose技术将Excel文件转换为PDF格式。我们将使用Aspose-Cells-8.5.2.jar包,并演示Java代码以及进行测试。 一、Aspose技术概述 Aspose是一款强大的文档处理库,支持多种编程语言,如Java、C#、Python等。…...
Opencv 色彩空间
一 核心知识 色彩空间变换; 像素访问; 矩阵的、-、*、、; 基本图形的绘制 二 颜色空间 RGB:人眼的色彩空间; OpenCV默认使用BGR; HSV/HSB/HSL; YUV(视频); 1 RGB 2 BGR 图像的多种属性 1 访问图像(Ma…...
FileZilla:不安全的服务器,不支持 FTP over TLS 原因与解决方法
今天在用FileZilla Client连接某个主机的FTP的时候,主机地址、账号、密码、端口确定百分之百正确的情况下,结果报错如下: 状态: 正在解析 x.x.x 的地址 状态: 正在连接 x.x.x.x:21... 状态: 连接建立,等待欢迎消息... 状态: 不安全…...
自定义注解实现Excel 导出
概述 一个用自定义注解实现导出字段定义的工具实现。 1. 注解定义,定义导出Excel的字段 Target(ElementType.FIELD) Retention(RetentionPolicy.RUNTIME) public interface PoiExportField {// Label of the columnString label();// Order of the column,default 0,means t…...
先求生存,再谋发展:俞敏洪的创业哲学与产品创新之路
引言: 在创业的道路上,每一个创业者都面临着无数的挑战和选择。俞敏洪,新东方教育科技集团的创始人,以其独特的创业哲学和坚韧不拔的精神,带领新东方从一个小小的培训机构成长为全球知名的教育品牌。他的成功经验告诉…...
【Spark】直接从DataFrame的schema创建表
// 基于DataFrame创建表 def createTable(dataFrame: DataFrame,partitionColumns: Array[String],databaseName: String,tableName: String): Unit = {...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
6.9-QT模拟计算器
源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
高保真组件库:开关
一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…...
Netty自定义协议解析
目录 自定义协议设计 实现消息解码器 实现消息编码器 自定义消息对象 配置ChannelPipeline Netty提供了强大的编解码器抽象基类,这些基类能够帮助开发者快速实现自定义协议的解析。 自定义协议设计 在实现自定义协议解析之前,需要明确协议的具体格式。例如,一个简单的…...
