企业营销型网站推广方法/广州seo网络培训课程
1. JSON 是什么
JSON(JavaScript Object Notation)是一个用于数据交换的文本格式,现时的标准为ECMA-404 。
虽然 JSON 源自于 JavaScript 语言,但它只是一种数据格式,可用于任何编程语言。现时具有类似功能的格式有XML、YAML,当中以 JSON 的语法最为简单。
例如,一个动态网页想从服务器获得数据时,服务器从数据库查找数据,然后把数据转换成 JSON 文本格式:
{"title": "Design Patterns","subtitle": "Elements of Reusable Object-Oriented Software","author": ["Erich Gamma","Richard Helm","Ralph Johnson","John Vlissides"],"year": 2009,"weight": 1.8,"hardcover:": true,"publisher": {"Company": "Person Education","Country": "India"},"website": null
}
网页的脚本代码就可以把此 JSON 文本解析为内部的数据结构去使用。
从此例子可看出,JSON 是树状结构,而 JSON 只包含 6 种数据类型:
- null:表示为 null
- boolean:表示为 true 或 false
- number:一般的浮点数表示方式,在下一单元详细说明
- string:表示为 “…”
- array:表示为 […]
- object:表示为 {…}
我们要实现的 JSON 库,主要是完成 3 个需求:
- 把 JSON 文本解析为一个树状数据结构(parse)。
- 提供接口访问该数据结构(access)。
- 把数据结构转换成 JSON 文本(stringify)。
我们会逐步实现这些需求。在本单元中,我们只实现最简单的 null 和 boolean 解析。
2. 搭建编译环境
源代码位于 kikajson,当中 01 为本单元的代码。
代码文件只有 3 个:
kikajson.h
:leptjson 的头文件(header file),含有对外的类型和 API 函数声明。kikajson.c
:leptjson 的实现文件(implementation file),含有内部的类型声明和函数实现。此文件会编译成库。test.c
:我们使用测试驱动开发(test driven development, TDD)。此文件包含测试程序,需要链接 leptjson 库。
为了方便跨平台开发,使用一个软件配置工具 CMake。
使用 Visual Studio 打开本单元项目,VS会自动进行CMake的配置(前提是已经VS已经安装好相应的插件),然后点开 CMakeLists.txt,运行当前文档,就可以编译运行了
编译运行后会出现:
D:\rep\kikajson\test.c:56: expect: 3 actual: 0
11/12 (91.67%) passed
若看到类似以上的结果,说明已成功搭建编译环境,可以去看看那几个代码文件的内容了。
3. 头文件与 API 设计
C 语言有头文件的概念,需要使用 #include
去引入头文件中的类型声明和函数声明。但由于头文件也可以 #include
其他头文件,为避免重复声明,通常会利用宏加入 include 防范(include guard):
#ifndef KIKAJSON_H__
#define KIKAJSON_H__/* ... */#endif /* KIKAJSON_H__ */
宏的名字必须是唯一的,通常习惯以 _H__
作为后缀。由于 leptjson 只有一个头文件,可以简单命名为 KIKAJSON_H__
。如果项目有多个文件或目录结构,可以用 项目名称_目录_文件名称_H__
这种命名方式。
如前所述,JSON 中有 6 种数据类型,如果把 true 和 false 当作两个类型就是 7 种,我们为此声明一个枚举类型(enumeration type):
typedef enum { KIKA_NULL, KIKA_FALSE, KIKA_TRUE, KIKA_NUMBER, KIKA_STRING, KIKA_ARRAY, KIKA_OBJECT } kika_type;
因为 C 语言没有 C++ 的命名空间(namespace)功能,一般会使用项目的简写作为标识符的前缀。通常枚举值用全大写(如 KIKA_NULL
),而类型及函数则用小写(如 kika_type
)。
接下来,我们声明 JSON 的数据结构。JSON 是一个树形结构,我们最终需要实现一个树的数据结构,每个节点使用 kika_value
结构体表示,我们会称它为一个 JSON 值(JSON value)。
在此单元中,我们只需要实现 null, true 和 false 的解析,因此该结构体只需要存储一个 kika_type。之后的单元会逐步加入其他数据。
typedef struct {kika_type type;
}kika_value;
C 语言的结构体是以 struct X {}
形式声明的,定义变量时也要写成 struct X x;
。为方便使用,上面的代码使用了 typedef
。
然后,我们现在只需要两个 API 函数:
(1)一个是解析 JSON:
int kika_parse(kika_value* v, const char* json);
传入的 JSON 文本是一个 C 字符串(空字符结尾字符串/null-terminated string),由于我们不应该改动这个输入字符串,所以使用 const char*
类型。
另一注意点是,传入的根节点指针 v 是由使用方负责分配的,所以一般用法是:
kika_value v;
const char json[] = ...;
int ret = kika_parse(&v, json);
返回值是以下这些枚举值,无错误会返回 KIKA_PARSE_OK
,其他值在下节解释。
enum {KIKA_PARSE_OK = 0,KIKA_PARSE_EXPECT_VALUE,KIKA_PARSE_INVALID_VALUE,KIKA_PARSE_ROOT_NOT_SINGULAR
};
(2)另一个是一个访问结果的函数,就是获取其类型:
kika_type kika_get_type(const kika_value* v);
4. JSON 语法子集
下面是此单元的 JSON 语法子集,使用 RFC7159 中的 ABNF 表示:
JSON-text = ws value ws
ws = *(%x20 / %x09 / %x0A / %x0D)
value = null / false / true
null = "null"
false = "false"
true = "true"
当中 %xhh
表示以 16 进制表示的字符,/
是多选一,*
是零或多个,()
用于分组。
第一行的意思是,JSON 文本由 3 部分组成,首先是空白(whitespace),接着是一个值,最后是空白。
第二行的意思是,所谓空白,是由零或多个空格符(space U+0020)、制表符(tab U+0009)、换行符(LF U+000A)、回车符(CR U+000D)所组成。
第三行的意思是,我们现时的值只可以是 null、false 或 true。
第四到六行指出了 null、false、 true 对应的字面值(literal)。
我们的解析器应能判断输入是否一个合法的 JSON。如果输入的 JSON 不合符这个语法,我们要产生对应的错误码,方便使用者追查问题。
在这个 JSON 语法子集下,我们定义 3 种错误码:
- 若一个 JSON 只含有空白,传回
KIKA_PARSE_EXPECT_VALUE
。 - 若一个值之后,在空白之后还有其他字符,传回
KIKA_PARSE_ROOT_NOT_SINGULAR
。 - 若值不是那三种字面值,传回
KIKA_PARSE_INVALID_VALUE
。
5. 单元测试
许多初学者在做编程练习时,都是以 printf
/cout
打印结果,再用肉眼对比结果是否乎合预期。但当软件项目越来越复杂,这个做法会越来越低效。一般我们会采用自动的测试方式,例如单元测试(unit testing)。单元测试也能确保其他人修改代码后,原来的功能维持正确(这称为回归测试/regression testing)。
常用的单元测试框架有 xUnit 系列,如 C++ 的 Google Test、C# 的 NUnit。我们为了简单起见,会编写一个极简单的单元测试方式。
一般来说,软件开发是以周期进行的。例如,加入一个功能,再写关于该功能的单元测试。但也有另一种软件开发方法论,称为测试驱动开发(test-driven development, TDD),它的主要循环步骤是:
- 加入一个测试。
- 运行所有测试,新的测试应该会失败。
- 编写实现代码。
- 运行所有测试,若有测试失败回到3。
- 重构代码。
- 回到 1
TDD 是先写测试,再实现功能。这样的好处是,实现只会刚好满足测试,而不会写了一些不需要的代码,或是没有被测试的代码。
但无论我们是采用 TDD,或是先实现后测试,都应尽量加入足够覆盖率的单元测试。
回到 kikajson 项目,test.c
包含了一个极简的单元测试框架:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kikajson.h"static int main_ret = 0;
static int test_count = 0;
static int test_pass = 0;#define EXPECT_EQ_BASE(equality, expect, actual, format) \do {\test_count++;\if (equality)\test_pass++;\else {\fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);\main_ret = 1;\}\} while(0)#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")static void test_parse_null() {kika_value v;v.type = KIKA_TRUE;EXPECT_EQ_INT(KIKA_PARSE_OK, kika_parse(&v, "null"));EXPECT_EQ_INT(KIKA_NULL, kika_get_type(&v));
}/* ... */static void test_parse() {test_parse_null();/* ... */
}int main() {test_parse();printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);return main_ret;
}
现时只提供了一个 EXPECT_EQ_INT(expect, actual)
的宏,每次使用这个宏时,如果 expect != actual(预期值不等于实际值),便会输出错误信息。
若按照 TDD 的步骤,我们先写一个测试,如上面的 test_parse_null()
,而 kika_parse()
只返回 KIKA_PARSE_OK
:
D:\rep\kikajson\test.c:27: expect: 0 actual: 1
1/2 (50.00%) passed
第一个测试因为 kika_parse()
返回 KIKA_PARSE_OK
,所以是通过的。
第二个测试因为 kika_parse()
没有把 v.type
改成 KIKA_NULL
,造成失败。我们再实现 kika_parse()
令到它能通过测试。
然而,完全按照 TDD 的步骤来开发,是会减慢开发进程。所以有时需要在这两种极端的工作方式取平衡。一种做法是在设计 API 后,先写部分测试代码,再写满足那些测试的实现。
6. 宏的编写技巧
关于 EXPECT_EQ_BASE
宏的编写技巧,简单说明一下。反斜线代表该行未结束,会串接下一行。而如果宏里有多过一个语句(statement),就需要用 do { /*...*/ } while(0)
包裹成单个语句,否则会有如下的问题:
#define M() a(); b()
if (cond)M();
elsec();/* 预处理后 */if (cond)a(); b(); /* b(); 在 if 之外 */
else /* <- else 缺乏对应 if */c();
只用 { }
也不行:
#define M() { a(); b(); }/* 预处理后 */if (cond){ a(); b(); }; /* 最后的分号代表 if 语句结束 */
else /* else 缺乏对应 if */c();
用 do while 就行了:
#define M() do { a(); b(); } while(0)/* 预处理后 */if (cond)do { a(); b(); } while(0);
elsec();
7. 实现解析器
有了 API 的设计、单元测试,终于要实现解析器了。
首先为了减少解析函数之间传递多个参数,我们把这些数据都放进一个 kika_context
结构体:
typedef struct {const char* json;
}kika_context;/* ... *//* 提示:这里应该是 JSON-text = ws value ws */
/* 以下实现没处理最后的 ws 和 KIKA_PARSE_ROOT_NOT_SINGULAR */
int kika_parse(kika_value* v, const char* json) {kika_context c;assert(v != NULL);c.json = json;v->type = KIKA_NULL;kika_parse_whitespace(&c);return kika_parse_value(&c, v);
}
暂时我们只储存 json 字符串当前位置,之后的单元我们需要加入更多内容。
若 kika_parse()
失败,会把 v
设为 null
类型,所以这里先把它设为 null
,让 kika_parse_value()
写入解析出来的根值。
kikajson 是一个手写的递归下降解析器(recursive descent parser)。由于 JSON 语法特别简单,我们不需要写分词器(tokenizer),只需检测下一个字符,便可以知道它是哪种类型的值,然后调用相关的分析函数。对于完整的 JSON 语法,跳过空白后,只需检测当前字符:
- n ➔ null
- t ➔ true
- f ➔ false
- " ➔ string
- 0-9/- ➔ number
- [ ➔ array
- { ➔ object
所以,我们可以按照 JSON 语法一节的 EBNF 简单翻译成解析函数:
#define EXPECT(c, ch) do { assert(*c->json == (ch)); c->json++; } while(0)/* ws = *(%x20 / %x09 / %x0A / %x0D) */
static void kika_parse_whitespace(kika_context* c) {const char *p = c->json;while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')p++;c->json = p;
}/* null = "null" */
static int kika_parse_null(kika_context* c, kika_value* v) {EXPECT(c, 'n');if (c->json[0] != 'u' || c->json[1] != 'l' || c->json[2] != 'l')return KIKA_PARSE_INVALID_VALUE;c->json += 3;v->type = KIKA_NULL;return KIKA_PARSE_OK;
}/* value = null / false / true */
/* 提示:下面代码没处理 false / true,将会是练习之一 */
static int kika_parse_value(kika_context* c, kika_value* v) {switch (*c->json) {case 'n': return kika_parse_null(c, v);case '\0': return KIKA_PARSE_EXPECT_VALUE;default: return KIKA_PARSE_INVALID_VALUE;}
}
由于 kika_parse_whitespace()
是不会出现错误的,返回类型为 void
。其它的解析函数会返回错误码,传递至顶层。
8. 关于断言
断言(assertion)是 C 语言中常用的防御式编程方式,减少编程错误。最常用的是在函数开始的地方,检测所有参数。有时候也可以在调用函数后,检查上下文是否正确。
C 语言的标准库含有 assert() 这个宏(需 #include <assert.h>
),提供断言功能。当程序以 release 配置编译时(定义了 NDEBUG
宏),assert()
不会做检测;而当在 debug 配置时(没定义 NDEBUG
宏),则会在运行时检测 assert(cond)
中的条件是否为真(非 0),断言失败会直接令程序崩溃。
例如上面的 kika_parse_null()
开始时,当前字符应该是 'n'
,所以我们使用一个宏 EXPECT(c, ch)
进行断言,并跳到下一字符。
初使用断言的同学,可能会错误地把含副作用的代码放在 assert()
中:
assert(x++ == 0); /* 这是错误的! */
这样会导致 debug 和 release 版的行为不一样。
另一个问题是,初学者可能会难于分辨何时使用断言,何时使用运行时错误(如返回错误值或在 C++ 中抛出异常)。简单的答案是,如果那个错误是由于程序员错误编码所造成的(例如传入不合法的参数),那么应用断言;如果那个错误是程序员无法避免,而是由运行时的环境所造成的,就要处理运行时错误(例如开启文件失败)。
9. 总结与练习
本文介绍了如何配置一个编程环境,单元测试的重要性,以至于一个 JSON 解析器的子集实现。以下是本单元的练习,解答在 01-exercise 中。
- 修正关于
KIKA_PARSE_ROOT_NOT_SINGULAR
的单元测试,若 json 在一个值之后,空白之后还有其它字符,则要返回KIKA_PARSE_ROOT_NOT_SINGULAR
。 - 参考
test_parse_null()
,加入test_parse_true()
、test_parse_false()
单元测试。 - 参考
kika_parse_null()
的实现和调用方法,解析 true 和 false 值。
10. 常见问答
1… 为什么使用宏而不用函数或内联函数?
因为这个测试框架使用了 __LINE__
这个编译器提供的宏,代表编译时该行的行号。如果用函数或内联函数,每次的行号便都会相同。另外,内联函数是 C99 的新增功能,本框架使用 C89。
其他常见问答将会从评论中整理。
相关文章:

从零开始的JSON库(1):启程
1. JSON 是什么 JSON(JavaScript Object Notation)是一个用于数据交换的文本格式,现时的标准为ECMA-404 。 虽然 JSON 源自于 JavaScript 语言,但它只是一种数据格式,可用于任何编程语言。现时具有类似功能的格式有X…...

【Java】数组
目录 1.数组的定义与初始化 2.遍历数组 3.认识null 4.引用变量 5.返回多个值 6.数组拷贝 7.数组逆序 8.数组填充 9.小练习 //将整形数组转化为字符串 //二分查找优化 //冒泡排序优化 10.二维数组 //遍历二维数组 //不规则的二维数组 1.数组的定义与初始化 int…...

【C++】非类型的模板参数,特化
目录 1.类型模板参数和非类型模板参数 2.特化 3. 模板的分离编译 4.模板的优缺点 1.类型模板参数和非类型模板参数 之前写模板传的都是类型——类型模板参数 现在想定义两个静态数组,数组长度不同,就可以用模板参数传数值而不是传类型 非类型模板…...

核方法(kernel Method)
核方法 核方法定义 一种能够将在原始数据空间中的非线性数据映射到高维线性可分的方法。 核方法的用处 1、低维数据非线性,当其映射到高维空间(feature space)时,可以用线性方法对数据进行处理。 2、线性学习器相对于非线性学…...

消息队列MQ用来做什么的,市场上主流的四大MQ如何选择?RabbitMQ带你HelloWorld!
文章目录MQ用来做什么的MQ会有什么样的麻烦MQ消息队列模式分类MQ消息队列常用协议市场主流四大MQRabbitMQ项目开发RabbitMQ中的组成部分MQ用来做什么的 省流 :系统解耦、异步调用、流量削峰 系统解耦 首先举例下面这个场景,现有ABCDE五个系统ÿ…...

2023年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(同步赛) A — E
2023年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(同步赛) 文章目录A -- A Xor B Problem题目分析codeB -- 吃苹果题目分析codeC -- n皇后问题题目分析codeD -- 分苹果题目分析codeE -- 完型填空题目分析codeA – A…...

一文分析Linux v4l2框架
说明: Kernel版本:4.14 ARM64处理器,Contex-A53,双核 使用工具:Source Insight 3.5, Visio 1. 概述 V4L2(Video for Linux 2):Linux内核中关于视频设备驱动的框架,对上向应用层提供…...

MFC常用控件使用(文本框、编辑框、下拉框、列表控件、树控件)
简介 本文章主要介绍下MFC常用控件的使用,包括静态文本框(Static Text)、编辑框(Edit Control)、下拉框(Combo Box)、列表控件(List Control)、树控件(Tree Control)的使用。 创建项目 我们选择 文件->新建->新建项目,选择MFC程序 选择基于对话…...

13 node 程序后台执行加上 tail 命令, 中断 tail 命令, 同时也中断了 node 程序
前言 呵呵 最近帮朋友解决问题[2022.09.08] 需要启动一个 node 程序, 然后 需要一个 startUp.sh 脚本 然后 反手写了一个过去, 按道理 来说 应该是 后台启动了对应的 node 程序, 然后将 标准输出, 错误输出 输出到 logs/nohup.log 日志文件中, 然后基于 tail 命令 来查看 …...

52癫痫发作预测的有效双自注意力残差网络
Effective dual self-attentional residual networks for epileptic seizure prediction 摘要 癫痫发作预测作为慢性脑疾病中最具挑战性的数据分析任务之一,引起了众多研究者的广泛关注。癫痫发作预测,可以在许多方面大大提高患者的生活质量࿰…...

【计算机网络】Tcp IP 面试题相关
互联网协议群(TCP/IP):多路复用是怎么回事? 1.【问题】IPv4 和 IPv6 有什么区别? IPv4 是用 32 位描述 IP 地址,理论极限约在 40 亿 IP 地址; IPv6 是用 128 位描述 IP 地址,IPv6 可…...

【MySQL】MySQL的存储引擎
目录 概念 分类 操作 概念 数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查 询、更新和删除数据。 不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能。现在 许多不同的数据库管理系统…...

es6动态模块import()
目录 一、语法说明 二、适用场合 三、注意点 四、示例代码 五、效果 一、语法说明 import命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行(import命令叫做“连接” binding 其实更合适)。 // 报错 if (x 2) {import MyMod…...

【Flask】Jinja2模板(十四)
Jinja2是一个单独的Python包,Flask依赖Jinja2,安装Flask时会自动安装Jinja2。Jinja2可以将数据和模板结合在一起生成动态文本。 一、引入 来看一个最简单的视图函数: app.route(/) def hello_world():return Hello World! 这个…...

Mr. Cappuccino的第49杯咖啡——冒泡APP(升级版)之基于Docker部署Gitlab
冒泡APP(升级版)之基于Docker部署Gitlab基于Docker安装Gitlab登录Gitlab创建Git项目上传代码使用Git命令切换Git地址使用IDE更换Git地址基于Docker安装Gitlab 查看beginor/gitlab-ce镜像版本 下载指定版本的镜像 docker pull beginor/gitlab-ce:11.3.0…...

《机器学习》基础概念之【P问题】与【NP问题】
《机器学习》基础概念之【P问题】与【NP问题】 这里写目录标题《机器学习》基础概念之【P问题】与【NP问题】一、多项式&时间复杂度1.1. 多项式1.2.时间复杂度二、P问题 & NP问题2.1. P问题2.2.NP问题2.3.举例理解NP问题-TSP旅行商推销问题三、NP-hard问题&NP-C问题…...

WinRAR安装教程
文章目录WinRAR安装教程无广告1. 下载2. 安装3. 注册4. 去广告WinRAR安装教程无广告 1. 下载 国内官网:https://www.winrar.com.cn/ 2. 安装 双击,使用默认路径: 点击“安装”。 点击“确定”。 点击“完成”。 3. 注册 链接ÿ…...

C++:vector和list的迭代器区别和常见迭代器失效问题
迭代器常见问题的汇总vector迭代器和list迭代器的使用vector迭代器list迭代器vector迭代器失效问题list迭代器失效问题vector和list的区别vector迭代器和list迭代器的使用 学习C,使用迭代器和了解迭代器失效的原因是每个初学者都需要掌握的,接下来我们就…...

SpringSecurity如何实现前后端分离
前后端分离模式是指由前端控制页面路由,后端接口也不再返回html数据,而是直接返回业务数据,数据一般是JSON格式。Spring Security默认的表单登录方式,在未登录或登录成功时会发起页面重定向,在提交登录数据时ÿ…...

为ubuntu 18.04添加蓝牙驱动
目录背景方法背景 从网上买的能直接插ubuntu 1804的usb蓝牙太少了,而且还贵。我就直接从JD下单的一个便宜的USB蓝牙,结果插上机器没有驱动起不来。我的PC是个3年前的老机器,实在是不想升级系统,于是捣鼓半天捣鼓好了,…...

Stable Diffusion Prompt用法
Stable Diffusion可以根据你输入的提示词(prompt)来绘制出想象中的画面。 1、正向提示词(Prompt): 提高图像质量的prompt: prompt用途HDR, UHD, 64K(HDR、UHD、4K、8K和64K)这样的质量词可以带来巨大的差异提升照片…...

jenkins问题
目录 python 不是内部或外部命令,也不是可运行的程序 ‘cmd’ 不是内部或外部命令,也不是可运行的程序或批处理文件。 git 不是内部或外部命令,也不是可运行的程序或批处理文件。 pywintypes.com_error: (-2147024891, ‘拒绝访问。’, None,…...

阅读笔记DeepAR: Probabilistic Forecasting with Autoregressive Recurrent Networks
zi,t∈Rz_{i,t}\in \mathbb{R}zi,t∈R表示时间序列iii在ttt时刻的值。给一个连续时间段t∈[1,T]t\in [1, T]t∈[1,T],将其划分为context window[1,t0)[1,t_0)[1,t0)和prediction window[t0,T][t_0,T][t0,T]。用context window的时间序列预测prediction window…...

01.Java的安装
1.JDK&JREJDK : Java SE Development Kit--Java开发工具JRE : Java Runtime Environment--Java运行环境Java编程,需要安装JDK;如果仅仅是运行一款Java程序则只需要运行JREJava的安装包分为两类:一类是JRE--是一个独立的Java运行环境; 一类…...

【C语言深度剖析】关键字(全)
文章目录一.存储类型关键字前言补充1:内存思考:补充2:变量与内存的关系补充3:变量的分类补充4:存储类补充5:删除数据是怎么删除的?1.auto2.register3.static4.extern基本用法:基本功能5.typedef…...

English Learning - L2 语音作业打卡 双元音 [aʊ] [əʊ] Day15 2023.3.7 周二
English Learning - L2 语音作业打卡 双元音 [aʊ] [əʊ] Day15 2023.3.7 周二💌发音小贴士:💌当日目标音发音规则/技巧:🍭 Part 1【热身练习】🍭 Part2【练习内容】🍭【练习感受】🍓元音 /eɪ…...

记第一次面试的过程(C++)
说实话三月份上旬过得很充实,而且感觉蛮值,但还有不足的地方,今晚特地看完资料分析来复盘复盘。 时间还要回到3.2中午13.35(别问我为什么那么准确,刚刚掏手机看的),我正在吃着饭看着王者荣耀的直…...

06 电力电子仿真 MATLAB/Simulink
文章目录01 单相半波整流电路02 单相全波整流电路(子系统封装模块)03 三相桥式整流电路(三相模块与示波器使用)04 相控与斩控交交调压(THD计算)05 Buck电路(PWM实现与闭环反馈)06 单…...

搞懂面向对象这五大概念,才算真正跨过初学者到开发者的“分水岭“
文章目录前言一、对象二、类三、面向对象程序设计的特点1. 封装2. 继承3. 多态前言 面向对象程序设计是在面向过程程序设计的基础上发展而来的,它比面向过程编程具有更强的灵活性和扩展性。面向对象程序设计也是一个程序员发展的 “分水岭”,很多的初学者…...

基于DelayQueue实现的延时队列
基于java中延时队列的实现该文章,我们这次主要是来实现基于DelayQueue实现的延时队列。 使用DelayQueue实现的延时队列的步骤: 定义一个继承了Delayed的类,定义其中的属性,并重写compareTo和getDelay两个方法创建一个Delayqueue…...