当前位置: 首页 > article >正文

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_conf_read_token - 详解(3)

详解(3)


if (last_space) {start = b->pos - 1;start_line = cf->conf_file->line;if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {continue;}switch (ch) {case ';':case '{':if (cf->args->nelts == 0) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"unexpected \"%c\"", ch);return NGX_ERROR;}if (ch == '{') {return NGX_CONF_BLOCK_START;}return NGX_OK;case '}':if (cf->args->nelts != 0) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"unexpected \"}\"");return NGX_ERROR;}return NGX_CONF_BLOCK_DONE;case '#':sharp_comment = 1;continue;case '\\':quoted = 1;last_space = 0;continue;case '"':start++;d_quoted = 1;last_space = 0;continue;case '\'':start++;s_quoted = 1;last_space = 0;continue;case '$':variable = 1;last_space = 0;continue;default:last_space = 0;}} else {if (ch == '{' && variable) {continue;}variable = 0;if (ch == '\\') {quoted = 1;continue;}if (ch == '$') {variable = 1;continue;}if (d_quoted) {if (ch == '"') {d_quoted = 0;need_space = 1;found = 1;}} else if (s_quoted) {if (ch == '\'') {s_quoted = 0;need_space = 1;found = 1;}} else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF|| ch == ';' || ch == '{'){last_space = 1;found = 1;}if (found) {word = ngx_array_push(cf->args);if (word == NULL) {return NGX_ERROR;}word->data = ngx_pnalloc(cf->pool, b->pos - 1 - start + 1);if (word->data == NULL) {return NGX_ERROR;}for (dst = word->data, src = start, len = 0;src < b->pos - 1;len++){if (*src == '\\') {switch (src[1]) {case '"':case '\'':case '\\':src++;break;case 't':*dst++ = '\t';src += 2;continue;case 'r':*dst++ = '\r';src += 2;continue;case 'n':*dst++ = '\n';src += 2;continue;}}*dst++ = *src++;}*dst = '\0';word->len = len;if (ch == ';') {return NGX_OK;}if (ch == '{') {return NGX_CONF_BLOCK_START;}found = 0;}}

这段代码是 Nginx 配置解析函数 ngx_conf_read_token 的核心部分,负责将配置文件内容拆分为 token(指令、参数、块等),并处理语法结构(如引号、变量、注释)。


if (last_space) {

  • 作用:判断是否处于 新 token 的起始状态last_space 为真时,表示上一个字符是空格或分隔符,当前可能开始新 token)。
  • 意义:进入新 token 的解析逻辑,初始化起始位置和行号

start = b->pos - 1;

  • 作用:记录当前 token 的 起始位置b->pos 是当前字符的下一个位置,-1 指向当前字符)。

start_line = cf->conf_file->line;

  • 作用:记录当前 token 的 起始行号
  • 意义
    • 当解析出错时(如未闭合的引号),Nginx 可通过 start_line 定位错误行,生成更精确的错误日志

if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {

  • 作用:检查当前字符是否为 空白字符(空格、制表符、回车、换行)。
  • 意义
    • 跳过连续的空白字符,避免将多个空格视为 token 的一部分。
    • Nginx 配置中参数由空格分隔,但连续空格会被视为单个分隔符

case ';'case '{'

  • 作用:处理分号 ; 或左花括号 { 的语法结构。
  • 意义
    • ; 表示 指令结束,如 listen 80;
    • { 表示 块开始,如 http { ... }
    • 这两个符号是 Nginx 配置的核心分隔符,用于界定指令和块的范围

if (cf->args->nelts == 0) { ... }

  • 作用:检查当前参数列表 args 是否为空。
  • 意义
    • args 为空(nelts == 0),则 ;{ 前没有有效指令,属于 语法错误(如 ;{ 孤立出现)。
    • 例如,配置文件中出现 ;{ 而无前置指令时,会触发此错误

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"%c\"", ch);

  • 作用:记录 紧急级别错误日志,提示意外字符。
  • 意义
    • 输出错误信息(如 unexpected ";"),帮助用户定位配置错误。
    • NGX_LOG_EMERG 表示最高优先级日志,确保错误不会被忽略

if (ch == '{') { return NGX_CONF_BLOCK_START; }

  • 作用:处理块开始符号 {
  • 意义
    • 返回 NGX_CONF_BLOCK_START 状态,通知上层函数进入 块解析模式
    • 例如,解析到 http { 时,后续内容会被视为 http 块的配置

return NGX_OK;

  • 作用:处理分号 ;,返回成功状态。
  • 意义
    • 表示当前指令解析完成(如 listen 80;),参数已存入 args 数组。
    • 上层函数(如 ngx_conf_handler)会进一步处理指令

case '}'

  • 作用:处理右花括号 },表示 块结束(如 http { ... } 的结束)。
  • 意义:触发块结束的逻辑验证,确保语法正确性

if (cf->args->nelts != 0) { ... }

  • 作用:检查参数列表 args 是否非空。
  • 意义
    • } 必须出现在参数列表为空时(如 server { ... }} 前无未处理参数)。
    • args 不为空(如 server { listen 80 } 缺少分号),则 } 是意外字符,属于语法错误

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");

  • 作用:记录 紧急级别错误日志,提示意外的 }
  • 意义
    • 明确告知用户配置文件中存在未闭合的块或多余参数。
    • 例如:server { listen 80 } 缺少 ;,导致 } 前仍有参数,触发此错误

return NGX_CONF_BLOCK_DONE;

  • 作用:返回块结束状态。
  • 意义
    • 通知上层函数(如 ngx_conf_parse)当前块解析完成,需退出当前层级,继续解析父块内容
    • 例如,解析完 http { ... } 后,返回此状态码,继续处理 http 块外的配置。


case '#':

  • 作用:处理 # 字符,表示 行注释开始
  • 意义
    • 设置 sharp_comment = 1,标记后续字符为注释,直到行尾(换行符 LF)。
    • continue 跳过后续逻辑,直接处理下一个字符

sharp_comment = 1;

  • 作用:标记当前处于 注释状态
  • 意义
    • 在后续循环中,所有字符(除换行符)均被跳过,直到换行符重置 sharp_comment

case '\\':

  • 作用:处理反斜杠 \,表示 转义字符

    • 设置 quoted = 1,标记下一个字符需要转义(如 \"\\)。
    • last_space = 0 表示当前字符非空格

case '"':

  • 作用:处理双引号 ",表示 字符串开始

    • start++ 跳过引号本身,指向字符串内容的起始位置。
    • d_quoted = 1 进入双引号模式,忽略内部空格和分隔符
    • 示例:"Hello World" 会被解析为一个完整 token,内部的空格不会分割参数。

case '\'':

  • 作用:处理单引号 ',表示 字符串开始

    • start++ 跳过引号本身,指向字符串内容的起始位置。
    • s_quoted = 1 进入单引号模式,功能与双引号类似,但不支持变量插值
    • 示例:'Hello World' 会被解析为一个完整 token。

case '$':

  • 作用:处理 $ 符号,表示 变量开始

    • 设置 variable = 1,标记当前处于 变量模式,允许后续字符包含 {(如 ${var}
    • 示例:$var${var} 会被识别为变量,支持复杂变量名。

default:

  • 作用:处理其他非特殊字符(如字母、数字、符号)。

    • last_space = 0 表示当前字符非空格

if (ch == '{' && variable) { continue; }

  • 作用:处理变量中的 { 字符。

    • 当处于变量模式(variable=1,如 ${var})时,允许 { 作为变量名的一部分,而非块开始符号。
    • continue 跳过当前循环,避免触发块开始逻辑,确保变量解析正确

variable = 0;

  • 作用:重置变量模式标志。

    • 确保变量模式仅在 $ 后生效,避免后续字符被错误识别为变量的一部分。
    • 例如,$var{test} 中的 { 会被视为普通字符,而非变量名的一部分

if (ch == '\\') { quoted = 1; continue; }

  • 作用:处理转义字符 \

    • 设置 quoted=1,标记下一个字符需要转义(如 \"\\)。
    • continue 跳过后续逻辑,直接处理转义后的字符,确保特殊字符被正确解析
    • 示例:\" 会被解析为普通双引号,而非字符串闭合符号。

if (ch == '$') { variable = 1; continue; }

  • 作用:处理变量符号 $

    • 设置 variable=1,进入变量模式,允许后续字符包含 {(如 ${var})。
    • continue 跳过后续逻辑,确保变量名正确解析


if (d_quoted) { ... }

  • 作用:检查是否处于 双引号包裹的字符串模式d_quoted=1)。

if (ch == '"') { ... }

  • 作用:检测双引号的闭合符号 "

当遇到未被转义的 " 时,结束双引号模式,准备结束当前 token


d_quoted = 0;

作用:退出双引号模式。

恢复普通解析逻辑,后续字符不再被视为字符串的一部分


need_space = 1;

作用:标记需要 空格或分隔符 结束当前 token。

  • 双引号闭合后,必须跟随空格、分号或花括号等分隔符,否则语法错误
  • 例如:"Hello"world 会因缺少分隔符触发错误。

found = 1;

作用:标记当前 token 解析完成。

触发后续代码将字符从 start 到当前位置复制到 args 数组中


else if (s_quoted) { ... }

作用:处理 单引号包裹的字符串模式s_quoted=1)。

  • 单引号内的内容会被视为完整 token,但不支持变量插值(如 '${var}' 会被保留原样)


if (ch == '\'') { ... }

  • 作用:检测单引号的闭合符号 '

  • 遇到未被转义的 ' 时,结束单引号模式


s_quoted = 0;

作用:退出单引号模式。

恢复普通解析逻辑,后续字符不再被视为单引号字符串的一部分


else if (ch == ' ' || ... || ch == '{') { ... }

  • 作用:处理 非引号模式下的分隔符(空格、换行符、;{)。

    • 这些字符标志着当前 token 的结束,触发参数提取
    • 例如:listen 80; 中的 ; 会结束 listen 80 的解析。

last_space = 1;

  • 作用:标记当前字符为 分隔符

    • 下一个非空白字符将被视为新 token 的起始位置
    • 例如:server { 中的空格会被标记为分隔符,{ 触发块开始。

found = 1;

  • 作用:标记当前 token 解析完成。
  • 意义
    • 触发后续代码将字符从 start 到当前位置复制到 args 数组中

if (found)

判断是否成功解析到一个完整的 token ,并触发后续处理逻辑。found 是一个状态标志,表示当前字符是否标志着 token 的结束


word = ngx_array_push(cf->args);

  • 作用:向动态数组 cf->args追加新元素,并返回指向该元素的指针。

  • 此处将解析出的 token(如指令、参数)存入 cf->args,供后续指令处理函数


if (word == NULL) { return NGX_ERROR; }

  • 作用:检查内存分配是否失败。

word->data = ngx_pnalloc(cf->pool, b->pos - 1 - start + 1);if (word->data == NULL) {return NGX_ERROR;}

从内存池 cf->pool 分配内存,存储当前解析的 token 内容。

检查内存分配是否失败。


for (dst = word->data, src = start, len = 0;src < b->pos - 1;len++){

for (dst = word->data, src = start, len = 0; ... )

初始化循环变量。

dst = word->data:指向新分配的内存地址,用于存储处理后的 token 内容
src = start:指向当前 token 在缓冲区中的起始位置
len = 0:初始化字符计数器,记录 token 的实际长度


src < b->pos - 1;

定义循环的终止条件。

b->pos:指向当前处理字符的下一个位置(因 b->pos 在解析时已递增)
src < b->pos - 1:确保循环处理从 start 到当前字符前一个位置的所有字符(避免越界)
示例:若 start 指向 lb->pos 指向 ;,则处理范围是 lnlisten 的最后一个字符)。


len++

在每次循环迭代后递增 len

统计已处理字符的数量,最终赋值给 word->len,表示 token 的实际长度


if (*src == '\\') {switch (src[1]) {case '"':case '\'':case '\\':src++;break;case 't':*dst++ = '\t';src += 2;continue;case 'r':*dst++ = '\r';src += 2;continue;case 'n':*dst++ = '\n';src += 2;continue;}

这段代码负责处理配置文件中的转义字符。
具体来说,它处理的是当遇到反斜杠 (\) 时,如何解析紧随其后的字符。以下是这段代码的详细解释:

  1. 检查当前字符是否为反斜杠 (\):

    • 如果当前字符是反斜杠 (\),则进入 switch 语句,检查下一个字符 (src[1])。

  2. 处理转义字符:

    • case '"': 如果下一个字符是双引号 ("),则跳过反斜杠,直接将双引号字符写入目标缓冲区 (dst)。这意味着 \" 被解释为一个普通的双引号字符。
    • case '\'': 如果下一个字符是单引号 ('),则跳过反斜杠,直接将单引号字符写入目标缓冲区 (dst)。这意味着 \' 被解释为一个普通的单引号字符。
    • case '\\': 如果下一个字符是反斜杠 (\),则跳过第一个反斜杠,直接将第二个反斜杠字符写入目标缓冲区 (dst)。这意味着 \\ 被解释为一个普通的反斜杠字符。
    • case 't': 如果下一个字符是 t,则将制表符 (\t) 写入目标缓冲区 (dst)。这意味着 \t 被解释为一个制表符。
    • case 'r': 如果下一个字符是 r,则将回车符 (\r) 写入目标缓冲区 (dst)。这意味着 \r 被解释为一个回车符。
    • case 'n': 如果下一个字符是 n,则将换行符 (\n) 写入目标缓冲区 (dst)。这意味着 \n 被解释为一个换行符。
  3. 更新指针:

    • 在处理完转义字符后,更新源指针 (src) 和目标指针 (dst) 的位置,以便继续处理后续字符。

if (ch == ';') {return NGX_OK;}if (ch == '{') {return NGX_CONF_BLOCK_START;}found = 0;

1. if (ch == ';') {
  • 作用:检查当前字符 ch 是否是一个分号 (;)。
  • 逻辑
    • 在 Nginx 配置文件中,分号 (;) 用于表示一个配置指令的结束。
    • 如果当前字符是分号,说明当前配置指令已经解析完毕。
  • 意图
    • 当遇到分号时,表示当前配置项已经完整解析,可以结束当前解析过程并返回成功状态。

2. return NGX_OK;
  • 作用:返回 NGX_OK,表示当前配置指令解析成功。
  • 逻辑
    • NGX_OK 是 Nginx 中定义的一个常量,表示操作成功。
    • 返回 NGX_OK 后,解析器会继续处理下一个配置指令。
  • 意图
    • 告诉调用者当前配置指令已经成功解析,可以继续处理后续内容。

3. if (ch == '{') {
  • 作用:检查当前字符 ch 是否是一个左大括号 ({)。
  • 逻辑
    • 在 Nginx 配置文件中,左大括号 ({) 用于表示一个配置块的开始。
    • 配置块通常包含一组相关的配置指令,例如 server 块或 location 块。
  • 意图
    • 当遇到左大括号时,表示当前配置指令是一个配置块的开始,需要进入块解析模式。

4. return NGX_CONF_BLOCK_START;
  • 作用:返回 NGX_CONF_BLOCK_START,表示当前配置指令是一个配置块的开始。
  • 逻辑
    • NGX_CONF_BLOCK_START 是 Nginx 中定义的一个常量,表示配置块的开始。
    • 返回 NGX_CONF_BLOCK_START 后,解析器会进入块解析模式,继续解析块内的配置指令。
  • 意图
    • 告诉调用者当前配置指令是一个配置块的开始,需要进一步解析块内的内容。

5. found = 0;
  • 作用:将变量 found 的值重置为 0
  • 逻辑
    • found 是一个标志变量,用于表示是否找到了一个完整的配置项(例如一个单词或一个字符串)。
    • 在解析过程中,found 可能被设置为 1,表示当前配置项已经解析完成。
    • 重置 found0 是为了准备解析下一个配置项。
  • 意图
    • 确保解析器在解析下一个配置项时,found 标志处于初始状态,避免影响后续解析逻辑。

这段代码的作用是处理配置文件中两个关键字符:分号 (;) 和左大括号 ({)。它们的含义如下:

  1. 分号 (;):表示当前配置指令的结束,解析器返回 NGX_OK,表示成功解析。
  2. 左大括号 ({):表示一个配置块的开始,解析器返回 NGX_CONF_BLOCK_START,表示进入块解析模式。
  3. 重置 found 标志:为解析下一个配置项做准备。

相关文章:

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_conf_read_token - 详解(3)

详解&#xff08;3&#xff09; if (last_space) {start b->pos - 1;start_line cf->conf_file->line;if (ch || ch \t || ch CR || ch LF) {continue;}switch (ch) {case ;:case {:if (cf->args->nelts 0) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,…...

私有云基础架构与运维(一)

私有云基础架构与运维&#xff08;OpenStackopenEuler版&#xff09; 项目一.OpenStack 云计算基础架构平台概述 任务1.1 安装部署虚拟化环境 通过安装 openEuler-22.09 操作系统来熟悉虚拟机的安装&#xff0c;在操作过程中熟悉计算机虚 拟化资源的分配管理。 1.1.1 VMware…...

代码随想录算法训练营第35天 | 01背包问题二维、01背包问题一维、416. 分割等和子集

一、01背包问题二维 二维数组&#xff0c;一维为物品&#xff0c;二维为背包重量 import java.util.Scanner;public class Main{public static void main(String[] args){Scanner scanner new Scanner(System.in);int n scanner.nextInt();int bag scanner.nextInt();int[…...

大学至今的反思与总结

现在是2025年的3月5日&#xff0c;我大三下学期。 自大学伊始&#xff0c;我便以考研作为自己的目标&#xff0c;有时还会做自己考研上岸头部985,211&#xff0c;offer如潮水般涌来的美梦。 但是我却忽略了一点&#xff0c;即便我早早下定了决心去考研&#xff0c;但并没有早…...

PySide(PyQT)的视图(QGraphicsView)范例(一) 基本框架

最近学习了视图&#xff08;QGraphicsView&#xff09;的知识&#xff0c;总结一下&#xff0c;做一个demo以备忘。在demo中演示了常用的设置方法和信号槽传递机制。 QT的视图&#xff08;QGraphicsView&#xff09;体系是建立在场景&#xff08;QGraphicsScene&#xff09;基础…...

深入理解seata使用和源码分析

一、数据库事务ACID特性 基础概念:事务ACID A(Atomic):原子性,构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失 败的情况。C(Consistency):一致性,在事务执行前后,数据库的一致性约束没有被破坏。比如:张三向李四转100元, 转账前和…...

centos8更换阿里云yum源

1.centos8更换为阿里云yum源 2.更换阿里云Yum-centos8源 mv /etc/yum.repos.d/CentOS-Stream-BaseOS.repo /etc/yum.repos.d/CentOS-Stream-BaseOS.repo.backupcurl -o /etc/yum.repos.d/CentOS-Stream-BaseOS.repo https://mirrors.aliyun.com/repo/Centos-8.repowget -O /et…...

单粒子翻转对FPGA的影响及解决方法

1 单粒子翻转对FPGA 的影响 对于在轨的空间应用而言,需要考虑外太空辐射对电子元器件带来的影响,包括单粒子翻转(Single Event Upset,SEU)、多粒子翻转(Multiple Bit Upset,MBU)、单粒子瞬态效应(Single Event Transient,SET)、单粒子功能中断(SingleEvent Functi…...

君正SOC芯片 T31X智能视频应用处理器 高集成度 超低功耗 提供软硬件资料+样品测试

君正&#xff08;Ingenic&#xff09;T31X是一款面向智能视频应用的高性能、低功耗处理器&#xff0c;适用于安防监控、智能家居和物联网等领域。以下是其主要技术参数&#xff1a; 1. 处理器&#xff08;CPU&#xff09;&#xff1a; 架构&#xff1a;XBurst-1内核主频&…...

基于Python Django的人脸识别上课考勤系统(附源码,部署)

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…...

论述AI对学习发展的改变(网页设计)

谈自己对AI看法 AI&#xff0c;即人工智能&#xff0c;是当今科技领域最具影响力和变革性的技术之一&#xff0c;对其看法可以从多个方面来探讨 积极方面 强大的技术能力 高效的数据处理出色的学习能力广泛的应用价值改善生活质量科学研究的有力助手加速科学发现 挑战和问题 伦…...

JS—组成:2分钟掌握什么是ECMAScript操作,什么是DOM操作,什么是BOM操作

个人博客&#xff1a;haichenyi.com。感谢关注 1. 目录 1–目录2–组成3–内置对象 2. 组成 一直都在说JS&#xff0c;JS&#xff0c;到底啥是JS有了解过吗&#xff1f;JS由哪几部分组成的呢&#xff1f; 定义&#xff1a; JavaScript是一种轻量级、解释型或即时编译型的编程语…...

Oracle数据库监听学习

官方文档&#xff1a; Net Services Administrators Guide Net Services Reference 一、动态注册 1.实例启动后&#xff0c;LREG 进程每分钟自动将服务名&#xff08;service_name&#xff09;注册到监听器中 也可以通过 alter system register 命令实现立刻注册。&#x…...

Vue Hooks 深度解析:从原理到实践

Vue Hooks 深度解析&#xff1a;从原理到实践 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff01;点我试试&#xff01;&#xff01; 文章目录 Vue Hooks 深度解析&#xff1a;从原理到实践一、背景…...

5c/c++内存管理

1. C/C内存分布 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const char* pChar3 "abcd";int* ptr1 (int*)malloc(sizeof(int) * 4);i…...

Android14 OTA差分包升级报Package is for source build

制作好差分包&#xff0c;使用adb线刷模式验证ota升级&#xff0c;出现E:Package is for source build错误 使用adb方式验证 进入recovery模式 adb reboot recovery稍等一会界面会提示 Now send the package you want to apply to the device with "adb sidelaod <…...

C++中的无锁编程

引言 在当今多核处理器普及的时代&#xff0c;并发编程已成为高性能应用程序开发的关键技术。传统的基于锁的同步机制虽然使用简单&#xff0c;但往往会带来性能瓶颈和死锁风险。无锁编程&#xff08;Lock-Free Programming&#xff09;作为一种先进的并发编程范式&#xff0c…...

7. 机器人记录数据集(具身智能机器人套件)

1. 树莓派启动机器人 conda activate lerobotpython lerobot/scripts/control_robot.py \--robot.typelekiwi \--control.typeremote_robot2. huggingface平台配置 huggingface官网 注册登录申请token&#xff08;要有写权限&#xff09;安装客户端 # 安装 pip install -U …...

设计模式 + java8方法引用 实现任意表的过滤器

会用到下面2个依赖&#xff0c;原因是在今天的案例中&#xff0c;我想在我代码中使用上Entity::getFieldName 这种形式 LambdaQueryWrapper<ApplicationDashboard> queryWrapper new LambdaQueryWrapper<>(); queryWrapper.eq(ApplicationDashboard::getAppCode,…...

分布式锁—5.Redisson的读写锁二

大纲 1.Redisson读写锁RedissonReadWriteLock概述 2.读锁RedissonReadLock的获取读锁逻辑 3.写锁RedissonWriteLock的获取写锁逻辑 4.读锁RedissonReadLock的读读不互斥逻辑 5.RedissonReadLock和RedissonWriteLock的读写互斥逻辑 6.写锁RedissonWriteLock的写写互斥逻辑…...

【C++设计模式】第七篇:桥接模式(Bridge)

注意&#xff1a;复现代码时&#xff0c;确保 VS2022 使用 C17/20 标准以支持现代特性。 抽象与实现的解耦之道 1. 模式定义与用途​​ 核心思想​ ​桥接模式&#xff1a;将抽象部分与实现部分分离&#xff0c;使二者可以独立变化。​关键用途&#xff1a; ​1.拆分复杂继承…...

Html常用代码

Html常用代码 文章目录 Html常用代码1-常用的Html代码1-Html模板 2-快速部署Live-Server1-Windows系统步骤 1&#xff1a;安装 Node.js步骤 2&#xff1a;安装 live - server步骤 3&#xff1a;使用 live - server 运行本地项目 2-Mac系统步骤 1&#xff1a;安装 Node.js步骤 2…...

c++中的一些控制符

控制符在<iomanip>头文件里 一、设置显示小数精度 &#xff1a;setprecision() float A3.1234&#xff1b; 默认有效位为6位&#xff0c;steprecision(3)→设置有效位为3位 【3.12】 可以与fixed搭配用&#xff0c;cout<<fixed<<setprecision(3)<&l…...

Go语言里面的堆跟栈 + new 和 make + 内存逃逸 + 闭包

在 Go 语言中&#xff0c;堆&#xff08;Heap&#xff09;和栈&#xff08;Stack&#xff09;是内存管理中的两个重要概念&#xff0c;它们在内存分配、数据存储和使用场景等方面存在明显差异。 栈&#xff08;Stack&#xff09; 栈是一种具有后进先出&#xff08;LIFO&#…...

蓝桥备赛(11)- 数据结构、算法与STL

一、数据结构 1.1 什么是数据结构&#xff1f; 在计算机科学中&#xff0c;数据结构是一种 数据组织、管理和存储的格式。它是相互之间存在一种 或多种特定关系的数据元素的集合。 ---> 通俗点&#xff0c;数据结构就是数据的组织形式 &#xff0c; 研究数据是用什么方…...

react 19版中路由react-router-dom v7版的使用

路由的安装&#xff1a; npm install react-router-dom在src目录下建一个router文件夹 在router文件夹里面建一个index.tsx index.tsx内容&#xff1a; import React from react; import {BrowserRouter as Router,Routes,Route,Link } from react-router-dom; import ManuLi…...

WPS工具栏添加Mathtype加载项

问题描述&#xff1a; 分别安装好WPS和MathType之后&#xff0c;WPS工具栏没直接显示MathType工具&#xff0c;或者是前期使用正常&#xff0c;由于WPS更新之后MathType工具消失&#xff0c;如下图 解决办法 将文件“MathType Commands 2016.dotm”和“MathPage.wll”从Matht…...

Tauri+React+Ant Design跨平台开发环境搭建指南

TauriReactAnt Design跨平台开发环境搭建指南 一、环境配置与工具链搭建 1.1 基础环境准备 必备组件&#xff1a; Rust工具链&#xff08;v1.77&#xff09;&#xff1a; curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh Node.js LTS&#xff08;v20.11.1&a…...

PDF转JPG(并去除多余的白边)

首先&#xff0c;手动下载一个软件&#xff08;poppler for Windows&#xff09;&#xff0c;下载地址&#xff1a;https://github.com/oschwartz10612/poppler-windows/releases/tag/v24.08.0-0 否则会出现以下错误&#xff1a; PDFInfoNotInstalledError: Unable to get pag…...

std::string的模拟实现

目录 string的构造函数 无参数的构造函数 根据字符串初始化 用n个ch字符初始化 用一个字符串的前n个初始化 拷贝构造 用另一个string对象的pos位置向后len的长度初始化 [ ]解引用重载 迭代器的实现 非const版本 const版本 扩容reserve和resize reserve resize p…...