0%

简介

  • 在C++编程中, NaN(Not a number)是浮点数类型(例如float, double, long double)中的一种特殊值,用于表示无法定义的数值或者操作结果。NaN在数值计算和科学计算中十分常见,正确理解和处理NaN对于编写健壮和可靠的代码至关重要。
Read more »

linux rsync命令是什么

rsync 是一个用于在本地或远程同步文件和目录的开源实用工具。它非常强大和灵活,支持递归传输、保持文件权限、压缩传输等功能,使其成为文件同步和备份的首选工具之一。

以下是 rsync 的一些常用选项和示例:

常用选项

  • -a, --archive:归档模式,等同于 -rlptgoD,保留文件的权限、时间戳、符号链接等。
  • -v, --verbose:详细模式,显示传输过程中的详细信息。
  • -z, --compress:在传输过程中压缩文件以节省带宽。
  • -P:显示传输进度并部分保留已传输的文件(等同于 --partial --progress)。
  • --exclude:排除指定的文件或目录。
  • --delete:删除目标目录中在源目录中不存在的文件。

基本用法

本地复制

1
rsync -av /source/directory /destination/directory

/source/directory 复制到 /destination/directory

远程复制

1
rsync -av /local/directory user@remote_host:/remote/directory

将本地目录 /local/directory 复制到远程主机 remote_host/remote/directory

1
rsync -av user@remote_host:/remote/directory /local/directory

将远程主机 remote_host/remote/directory 复制到本地目录 /local/directory

使用 --exclude 排除特定目录

1
rsync -av --exclude 'exclude_directory' /source/directory user@remote_host:/remote/directory

将本地目录 /source/directory 复制到远程主机 remote_host/remote/directory,但排除 exclude_directory 目录。

示例

  1. 同步本地目录

    1
    rsync -av /home/user/data /backup

    /home/user/data 目录同步到 /backup 目录。

  2. 排除特定目录

    1
    rsync -av --exclude 'tmp' /home/user/data /backup

    /home/user/data 目录同步到 /backup 目录,但排除 tmp 目录。

  3. 同步到远程主机

    1
    rsync -avz /home/user/data user@remote_host:/backup

    将本地 /home/user/data 目录同步到远程主机 remote_host/backup 目录,并在传输过程中进行压缩。

  4. 从远程主机同步到本地

    1
    rsync -avz user@remote_host:/backup /home/user/data

    将远程主机 remote_host/backup 目录同步到本地的 /home/user/data 目录,并在传输过程中进行压缩。

  5. 显示进度

    1
    rsync -avP /home/user/data user@remote_host:/backup

    将本地 /home/user/data 目录同步到远程主机 remote_host/backup 目录,并显示传输进度。

结论

rsync 是一个非常强大且灵活的工具,适用于各种文件同步和备份需求。通过熟练使用 rsync 的各种选项,你可以高效地完成复杂的文件传输和同步任务。

linux rsync命令 详解

rsync 是一个强大的文件同步工具,常用于在本地或远程主机之间复制和同步文件和目录。它支持增量传输、保持文件权限、压缩传输等功能。以下是 rsync 的详细说明和一些示例。

基本语法

1
rsync [OPTION]... SRC [SRC]... DEST
  • SRC:源文件或目录
  • DEST:目标文件或目录

常用选项

  • -a, --archive:归档模式,相当于 -rlptgoD,保留文件属性。
    • -r, --recursive:递归处理目录。
    • -l, --links:保留符号链接。
    • -p, --perms:保留文件权限。
    • -t, --times:保持文件修改时间。
    • -g, --group:保留文件组信息。
    • -o, --owner:保留文件所有者信息。
    • -D:保留设备文件和特殊文件。
  • -v, --verbose:详细输出。
  • -z, --compress:在传输过程中压缩文件。
  • -P:显示传输进度和部分传输的文件(等同于 --partial --progress)。
    • --partial:保留部分传输的文件,以便恢复。
    • --progress:显示传输进度。
  • --exclude:指定排除的文件或目录模式。
  • --delete:删除目标目录中在源目录中不存在的文件。
  • --bwlimit=RATE:限制 I/O 带宽,单位为 KB/s。
  • -e, --rsh=COMMAND:指定远程 shell 程序。
  • --checksum:基于文件校验和进行比较,而不是文件大小和修改时间。

示例

本地复制

将本地目录 /source/directory 复制到 /destination/directory

1
rsync -av /source/directory /destination/directory

远程复制

将本地目录 /local/directory 复制到远程主机 remote_host/remote/directory

1
rsync -av /local/directory user@remote_host:/remote/directory

将远程主机 remote_host/remote/directory 复制到本地目录 /local/directory

1
rsync -av user@remote_host:/remote/directory /local/directory

排除特定目录

将本地目录 /source/directory 复制到远程主机 remote_host/remote/directory,但排除 exclude_directory

1
rsync -av --exclude 'exclude_directory' /source/directory user@remote_host:/remote/directory

显示进度

在传输过程中显示进度:

1
rsync -avP /source/directory user@remote_host:/remote/directory

同步文件并删除目标目录中多余的文件

将本地目录 /source/directory 同步到远程主机 remote_host/remote/directory,并删除目标目录中多余的文件:

1
rsync -av --delete /source/directory user@remote_host:/remote/directory

限制传输带宽

将本地目录 /source/directory 复制到远程主机 remote_host/remote/directory,并限制传输带宽为 500 KB/s:

1
rsync -avz --bwlimit=500 /source/directory user@remote_host:/remote/directory

使用 SSH 进行传输

通过 SSH 进行文件传输:

1
rsync -avz -e ssh /source/directory user@remote_host:/remote/directory

基于校验和进行比较

基于文件校验和进行比较,而不是文件大小和修改时间:

1
rsync -avz --checksum /source/directory user@remote_host:/remote/directory

结论

rsync 是一个非常强大且灵活的工具,可以满足各种文件同步和备份需求。通过掌握 rsync 的各种选项和用法,你可以高效地完成复杂的文件传输和同步任务。

linux rsync命令 拷贝目录并且忽略指定目录

在 Linux 上使用 rsync 拷贝目录并且忽略指定目录的具体步骤如下。假设你要拷贝 /source/directory 到目标目录 /destination/directory,但要忽略 ignore_directory 目录。

示例命令

1
rsync -av --exclude 'ignore_directory' /source/directory/ /destination/directory/

详细说明

  • -a, --archive:归档模式,表示递归复制目录,并保持文件属性。
  • -v, --verbose:详细模式,显示传输过程中的信息。
  • --exclude 'ignore_directory':指定要排除的目录 ignore_directory
  • /source/directory/:源目录路径,末尾的 / 表示拷贝目录内的内容。
  • /destination/directory/:目标目录路径,末尾的 / 表示将内容复制到该目录中。

更详细的例子

假设有如下目录结构:

1
2
3
4
5
6
/source/directory/
├── file1.txt
├── file2.txt
└── ignore_directory/
├── file3.txt
└── file4.txt

使用上述 rsync 命令:

1
rsync -av --exclude 'ignore_directory' /source/directory/ /destination/directory/

结果是:

1
2
3
/destination/directory/
├── file1.txt
└── file2.txt

其他选项

  • 如果你有多个目录或文件需要排除,可以使用多个 --exclude 选项:
1
rsync -av --exclude 'ignore_directory1' --exclude 'ignore_directory2' /source/directory/ /destination/directory/
  • 你也可以使用 --exclude-from 选项从文件中读取排除的目录和文件列表。假设排除列表文件 exclude-list.txt 内容如下:
1
2
3
ignore_directory1
ignore_directory2
ignore_file.txt

使用命令:

1
rsync -av --exclude-from='exclude-list.txt' /source/directory/ /destination/directory/

结论

通过以上方法,你可以使用 rsync 高效地复制目录,同时忽略指定的目录或文件。这些选项提供了灵活的排除机制,使 rsync 成为处理文件同步和备份任务的强大工具。

linux rsync命令 远程拷贝目录并且忽略指定目录

使用 rsync 命令可以实现远程拷贝目录并且忽略指定目录。以下是详细步骤和示例。

示例命令

假设你要将本地的 /source/directory 目录拷贝到远程主机 remote_host/destination/directory,但要忽略 ignore_directory 目录。

1
rsync -av --exclude 'ignore_directory' /source/directory/ user@remote_host:/destination/directory/

详细说明

  • -a, --archive:归档模式,表示递归复制目录,并保持文件属性。
  • -v, --verbose:详细模式,显示传输过程中的信息。
  • --exclude 'ignore_directory':指定要排除的目录 ignore_directory
  • /source/directory/:源目录路径,末尾的 / 表示拷贝目录内的内容。
  • user@remote_host:/destination/directory/:目标目录路径,格式为 user@host:/path

更详细的例子

假设有如下本地目录结构:

1
2
3
4
5
6
/source/directory/
├── file1.txt
├── file2.txt
└── ignore_directory/
├── file3.txt
└── file4.txt

使用上述 rsync 命令:

1
rsync -av --exclude 'ignore_directory' /source/directory/ user@remote_host:/destination/directory/

结果是远程主机 remote_host 上的 /destination/directory/ 目录结构为:

1
2
3
/destination/directory/
├── file1.txt
└── file2.txt

使用多个排除选项

如果你有多个目录或文件需要排除,可以使用多个 --exclude 选项:

1
rsync -av --exclude 'ignore_directory1' --exclude 'ignore_directory2' /source/directory/ user@remote_host:/destination/directory/

使用排除列表文件

你也可以使用 --exclude-from 选项从文件中读取排除的目录和文件列表。假设排除列表文件 exclude-list.txt 内容如下:

1
2
3
ignore_directory1
ignore_directory2
ignore_file.txt

使用命令:

1
rsync -av --exclude-from='exclude-list.txt' /source/directory/ user@remote_host:/destination/directory/

结论

通过以上方法,你可以使用 rsync 高效地实现远程目录拷贝,同时忽略指定的目录或文件。这些选项提供了灵活的排除机制,使 rsync 成为处理远程文件同步和备份任务的强大工具。

简介

  • 计算机视觉(Computer Vision, CV)。
  • CV算法工程师负责设计,开发和优化各种算法,以处理和分析图像和视频数据。

图像获取

  • 提取二维图像,三维图组,图像序列或相关的物理数据,例如声波,电磁波或核磁共振的深度,吸收度或反射度。

预处理

  • 对图像作一种或一些预处理,使图像满足后继处理的要求,例如: 二次取样保证图像坐标的正确,平滑去噪等。

特征提取

  • 从图像中提取各种复杂度的特征,例如,线,边缘提取和脊检测,边角检测,斑点检测等局部化的特征点检测

检测/分割

  • 对图像进行分割,提取有价值的内容,用于后继处理,例如:筛选特征点,分割含有特定目标的部分。

高级处理

  • 验证得到的数据是否匹配前提要求,估测特定系数,对目标进行分类。

数学基础知识

  • 线性代数: 矩阵运算,特征值与特征向量,向量空间等
  • 微积分: 导数,梯度,偏导数,泰勒级数等
  • 概率论与数理统计: 随即变量,概率分布,期望,方差,协方差,贝叶斯定理等
  • 优化理论: 梯度下降,牛顿法,拟牛顿法,拉格朗日乘数法等

编程基础知识

  • Python: 掌握Python基础语法,熟悉Numpy,Pandas,Matplotlib等库
  • C/C++: 理解指针,内存管理,面向对象编程等概念,用于算法的高效实现
  • OpenCV: 学习OpenCV库的使用,熟悉图像处理和计算机视觉的基础操作。

计算机视觉技术

  • 图像处理

    • 图像增强: 灰度变换,直方图均衡化,滤波等
    • 图像分割:阈值分割,边缘检测,区域生长等
    • 图像特征提取:角点检测,SIFT,SURF,ORB等
  • 计算机视觉算法

    • 目标检测: R-CNN系列(R-CNN, Fast R-CNN, Faster R-CNN), YOLO系列,SSD等
    • 图像识别: CNN(卷积神经网络),ResNet,VGG,MobileNet等
    • 图像生成: GAN(生成对抗网络),VAE(变分自编码器)等
    • 三维视觉: 立体视觉,结构光,深度估计等
  • 深度学习框架

    • TensorFlow: 学习TensorFlow的基础使用,熟悉其高级API(例如Keras)和底层实现
    • PyTorch: 掌握Pytorch的动态图特性,熟悉其网络设计和优化工具

简介

  • 机器人视觉,计算机视觉,图像处理,机器视觉和图形识别

什么是机器人视觉(Robot Vision)

  • 机器人视觉是指使机器人具有视觉感知功能的系统,是机器人系统组成的重要部分之一。在基本术语中,机器人视觉涉及使用相机硬件和计算机算法的结合,让机器人处理来自现实世界的视觉数据。例如,您的系统可以使一个二维摄像头,检测到机器将拿起来的一个对象物,更复杂的例子可能是使用一个3D立体相机来引导机器人将车轮安装到一个移动中的车辆上。

信号处理(Signal Processing)

  • 信号处理包括处理电子信号、或是清理(例如:除噪)、提取信息、为输出到显示端的前置预处理、或者为他们的进一步处理做准备的预处理。任何东西都可以是一个信号,或多或少,有各种类型的信号可以被处理,例如:模拟信号,数字信号,频率信号等等,图像基本上只是二维(或更多维)的信号,对于机器人视觉,我们感兴趣的是针对图像的处理。

图像处理与计算机视觉(Image Processing vs Computer Vision)

  • 图像处理技术主要是用来提高图像的质量,将其转换成另外一种格式(如直方图)或改变它以进一步处理。另一方面,计算机视觉更侧重于从图像中提取信息,以感知它们。因此,您可能会使用图像处理将彩色图像转换为灰度图像,然后用计算机视觉检测图像中的对象。如果我们再进一步往上看这个族谱,我们看到,这两个领域都受物理领域很大的影响特别是光学。

图形识别与机器学习(Pattern Recognition and Machine Learning)

  • 这个分支专注于识别数据中的图形,对于需要机器人视觉相对更先进的功能来说这是相当重要的。例如,为了能够从它的图像中识别一个对象,该软件必须能够监测到它所看到的对象是不是之前看到过的对象。因此,机器学习是计算机视觉除信号处理之外的另外一个母体。
  • 然而,并不是所有的计算机视觉技术都需要机器学习,你也可以仅使用信号而不是图像进行机器学习,然后将其作为一个Input输入到机器学习算法。例如。计算机视觉检测到传送带上的零件大小和颜色,然后机器学习根据它从正常的良品看起来应该是什么样子学到的知识,来判定这些零件是不是不良品。

机器视觉(Machine Vision)

  • 现在我们谈到机器视觉,一切都将改变。这是因为机器视觉完全不同于之前谈到的术语。它更侧重于特定的应用,而不仅仅是关注技术的部分,机器视觉是指工业用途的视觉来进行自动检测、过程控制和机器人导引。族谱的其余部分是科学领域,而机器视觉是一个工程领域。
  • 某种程度上来说,你可以认为机器视觉是计算机视觉的孩子,因为它使用计算机视觉和图像处理的技术和算法。但是,虽然它可以用来指导机器人的,他又不完全是机器人视觉。

简介

  • C++工程师求职简历

简历避坑

  • 容易犯的错误

    • 把校招的简历改一改直接发给我的,说实话,我社招是不会看你的社团经历的,没有什么太大的价值,还有你在学校获的那些精神文明奖项,更没有意义了
    • 写一个大段的有点重复的,都是套话的自我评价,我已经都会背了
    • 第一份工作经历写得一塌糊涂的,没有结果没有产出,给我列了一堆工作内容,这不是你的工作汇报报告,看这些东西没有价值
  • 有过工作经验与应届生的简历还是要有很大区别。你在职场中的历练即使只有短短的一年时间,对于用人单位来说也算是有工作经验,更何况你已经任职了几年的时间,这些经历写在简历中,这些对于你寻找新的工作都是非常有益处的。如果你面临第一次跳槽,把简历从文档中“捞”出来,重新润色

  • 重新撰写简历可以考虑删减掉在校经历,只要体现你的最高学历和所学专业即可。例如:学习状况;校内社团学生会活动经历;隐去在校内的职务,毕竟这些只是代表你在学生时期的一定历练,对于工作多年的职场人并不适用。如果是真的没什么好写的内容,那就还是选择写上吧……就当充数了。

  • 刷新职场中的工作经历:将职场中的工作经历详尽描述。几年的工作时间一定累计了相应的工作经验,针对自己的岗位职责,工作成绩做到有条理的陈述,并将工作中取得的成绩用数据、百分比进行详细阐述。如果有明确的项目执行经验,简历中最好也明确表述。仅仅用职位头衔并不能让HR更直观的看出一个人的实际能力,是否是公司所需要的人才,高质量的项目执行经验会为简历增色不少。用直观的数字体现你获得的成就、业绩。把自己获得过的奖项之类都可以放到简历上,会让HR更加鲜明地感受到你的优秀。

  • 认真的表达你第一次跳槽的原因.金三银四最适合找工作的黄金时间段,金三银四的大意是:最好的时间是三月,其次是四月.同理于金九银十,最好的时间是九月,其次是十月

  • 为什么要更写简历?

    • 简历,他可以吸引适合你的公司,也能够过滤调不适合你的公司.
    • 简历的第一个原则就是表现真实的自己
  • 突出自己的优势

    • 如果你第一次跳槽,那么,在制作简历时,一定要清除地认识到自己的短处所在,并用其他优势条件来弥补,扬长避短.例如突出从事的职业及所取得的工作成绩:
      • 你在这段时期作了什么
      • 获得了什么成就
      • 主导了某个项目
      • 承担了核心工作等
      • 但凡你觉得比较亮眼的点,都记得一定要写上
  • 写出自己的职业规划

    • 部分HR会认为频繁跳槽的求职者是因为没有清晰的职业规划路径,不知道自己向干什么,所以才通过频繁的还工作来寻找适合自己的岗位
    • 因此,在写求职简历的时候,可以简单说说自己的职业规划是怎样的,之前多次跳槽也是为了修正自己的职业路径,目标公司那里符合自己的职业规划,自己希望在这家工作多久等
  • 诚实表达自己的跳槽意图

    • 对于非主观自愿的原因,例如公司倒闭,部门解散,家庭原因等,如实告知即可,对于此类原因,企业一般不会有什么意见
    • 而对于一些主观原因,自己主动离职,也尽量不要隐瞒,但是可以从自己的职业发展方向出发,让企业或者HR能够对你产生认同感.
  • 如果自己没有头绪,就花点小钱,找人帮你修改.

  • 项目经验:突出你在过去的三到四年中参与和完成的项目。描述你的角色、项目规模、使用的技术和工具,并强调你取得的成果和贡献。包括具体的项目细节和解决方案,以及任何与项目相关的指标或指导性数据

  • 技能和技术栈:列出你熟悉的编程语言、框架、库和工具。强调你对Python的扎实掌握以及相关的Web开发、数据库管理、测试框架、版本控制系统等方面的技能。如果你有其他编程语言或领域专长(如数据科学、机器学习等),也应在技能部分进行适当的展示

  • 贡献和成果:突出你在工作中取得的具体成果和贡献。这可能包括优化性能、提高系统可靠性、实施新功能或改进现有功能等方面的工作。使用具体的数字和数据来量化你的成就,如优化代码效率带来的性能提升、减少bug数量、增加用户数量等

  • 自我学习和持续发展:强调你对技术的持续学习和成长。提及你参与的培训、研讨会、技术社区的活动,以及你通过阅读书籍、学习新技术等方式自我提升的经验。这展示了你对个人发展和保持行业领先的承诺

个人优势

  • 一年软件开发经验。熟悉C,C++,Python技术,熟悉Linux下常用操作,熟悉gcc,g++,gdb,cmake,bash,git,熟悉VSCode,vim的使用,熟悉HTTP网络通讯协议,RS-485通讯协议,熟悉Sqlite3,数据库常用操作,TCP/IP协议,WebSocket网络通讯协议,Zmq,Kafka通讯协议,有OpenCV和FFmpeg开发经验。熟悉机器人学理论基础,例如世界坐标系,关节空间,末端工具空间,Move Joint, Move Line等,使用Eigen库,对欧拉角,轴角,旋转矩阵常用姿态的表示和转换。熟悉docker常用命令和项目部署。英语四级,抗压能力强,有良好的团队协作能力,沟通能力。

项目经历

  • 打磨两个产品:
    • RK平台下的边缘计算产品
    • 协作机器人的底层服务器

边缘计算项目总结

  • 项目名称: 智慧工地视频分析盒子
  • 项目介绍: 智慧工地视频分析盒子采用Rockchip(瑞芯微)的1126芯片,是一款低功耗,低成本的边缘盒子产品。支持云连接,四种AI算法,主要应用于智慧工地场景。出货量40+
  • 技术栈:
    • 第三方开源库: mongoose, sqlite3, opencv, ffmpeg, cpp-httplib, nlohmann/json
    • 产品部署: docker, python scripts, shell scripts, frp
    • 难点: 多任务管理和视频播放,服务稳定性
  • 工作和成就:
    • 负责后端服务器开发,视频流分析和实现检测业务,两个月的时间从零设计,开发,测试并发布。
    • 负责产品功能迭代,对接推送协议,告警音柱,售后支持等工作。对接的平台有南京傲途,常州启安,杭州新中大,苏州傲之途等,对接的音柱厂家有妙音,隽声。部署盒子40+

机器人项目总结

  • 项目名称: 机场行李搬运项目
  • 项目介绍: 机场行李搬运项目以AI+机器人为目标,用机械臂代替人工,完成行李从传送带到行李车的装载工作。主要的硬件设备为 泰科机械臂,图漾3D相机,钧舵电动吸盘。
  • 技术栈:
    • 第三方开源库: mongoose, boost.asio, STL, nlohmann/json, glog, gflags, opencv, eigen, cpp-httplib, openssl
    • 难点: 机械臂末端姿态控制,行李搬运业务
  • 工作和成就:
    • 整个项目大致分为三个模块,前端,后端,底层服务。底层服务分为六个模块,分别是:内核模块,机械臂模块,工具模块,相机模块,任务模块,算法模块。我负责内核模块,机械臂模块,任务模块的设计和开发工作。
    • 完成了第一版任务编排数据结构设计,提供前端拖拽式编程功能接口;从零学习机械臂相关理论,封装不同机械臂SDK,向上提供统一的控制接口,完成手眼标定算法工程化,解决末端姿态控制问题;独立完成行李搬运业务,克服急停开发问题。团队完成具有动态抓取,智能码垛,手眼标定,目标测速,3D仿真等功能的机场行李搬运项目1.0版本

简介

  • 边缘计算项目的总结文档

  • 项目名称: 智慧工地视频分析盒子

  • 项目需求: 智慧工地盒子产品实现对工地现场中一些违规现象及时发现和提醒,提高管理效率

人员分工

  • 前端页面
  • 后端服务器
  • 底层视频结构化引擎

硬件配置

  • 工地智能盒子为ARM平台,处理器内置NPU,带2T算力,运行AI模型进行视频分析

明确你的项目的整体架构,在面试的时候能够清除的画给面试官看并清除的指出从哪里调用到那里,使用什么方式调用

  • 前端和后端通过HTTP协议通讯,接口规范为REST ful接口
  • 后端与引擎通过HTTP协议通讯,图片数据通过共享内存的方式传输
  • 盒子后台管理系统有以下几个模块
    • 摄像头管理,对摄像头进行增加,删除,修改
    • 任务管理,对任务的创建,启动,停止,修改
    • 告警管理,对告警信息的统计
    • 盒子信息,对盒子本身硬件信息的展示
    • 系统配置,对盒子告警推送的云平台地址的创建,删除,修改

明确你的模块在整个项目中所处的位置及作用

  • 我负责的模块是后端服务器

  • 后端服务器向前端提供数据支持,

    • 告警数据的上报
    • 视频播放
  • 与底层引擎交互,对结构化数据的处理

    • 任务管理
    • 图片的结构化数据处理,告警业务实现

明确你的模块用到了那些技术,更好一些的,可以再了解一下整个项目用到了那些技术

  • 后端服务器和前端的通讯

    • mongoose静态文件托管
    • mjpeg图片传输,图片数据+结构化数据
    • 多任务视频播放,视频切换
    • ip 子网掩码 解析和回显 std::bitset<>
    • sqlite3 数据库操作
  • 后端服务器与底层引擎的通讯

    • pthread_setname_np(), std::thread::native_handle()
    • opencv cv::imencode(), base64编码
    • httplib库 使用
    • 共享内存系统API
    • 图片传输,读者写者问题,后端服务器为读者,底层引擎为写者
    • 业务分析,目标是否在检测区域内

理论知识点

  • C++的二进制数据处理std::bitset, sqlite3, SQL, opencv, httplib, share memory

简介

  • 机器人项目的总结

  • 项目名称: 机场行李搬运项目

  • 项目需求: 机械臂替代人工,完成行李从传送带到行李车的装载工作

项目的需求分析

  • 难点

    • 行李箱形状不同,并要求无伤抓取
    • 传送带一直工作,行李箱处于移动状态
    • 行李传输为流水作业,要求系统各个部件容错性高
  • 系统功能

    • 动态抓取
    • 智能码垛

人员分工

  • 3D抓取算法,测速算法
  • 码垛算法
  • 机械臂控制,整体抓取流程集成(me)
  • 相机手眼标定,算法接入,末端工具接入,滑轨接入
  • 后台管理
  • 前端界面

明确这个项目到底是做什么的,有哪些功能

  • 这个项目是在机场环境下,使用机械臂代替人工,将行李箱由传送带搬运到运货车上的控制系统。整个系统是B/S架构。
  • 它具有视觉检测,自动抓取,智能放置功能。

明确你的项目的整体架构,在面试的时候能够清除的画给面试官看并清除的指出从哪里调用到那里,使用什么方式调用

  • 项目的整体架构有
    • front-end
    • back-end
    • server:
      • master
      • robot
      • eoat
      • camera
      • job
      • infer

明确你的模块在整个项目中所处的位置及作用

  • 我负责的模块是

    • master
    • robot
    • job
  • master

    • 内核节点,负责向后端提供REST ful接口,用于数据交互,与其他模块通讯,负责命令分发和数据处理
  • robot

    • 机械臂节点,负责封装机械臂服务,向其他模块提供机械臂命令
  • job

    • 任务节点,负责任务编排和抓取流程的实现

明确你的模块用到了那些技术,更好一些的,可以再了解一下整个项目用到了那些技术

  • 每个节点有一个难点

  • master

    • boost.asio库 线程池。用于避免每次HTTP请求时申请线程,是根据硬件最大并发数量预先申请好的线程资源。
    • mongoose库 处理HTTP请求数据,将外界数据转为内部数据结构,事件分发的机制
    • mongoose库 异步监听HTTP请求
    • std::atomic HTTP服务器退出信号处理
    • std::lock_guardstd::mutex 自动锁,更新设备清单时,读者与写者
    • reinterpret_cast<>() 数据重新解释,类型转换的知识点
    • nlohmann::json json数据的处理
    • std::tuple, std::tie 多类型返回值处理
    • std::find_if, STL算法库的使用
  • robot

    • 状态机,std::atomic
    • 工厂模式,动态多态,不同类型机械臂抽象出相同的接口函数,封装和继承
    • 机械臂理论知识
  • job

    • 动态多态
    • 基于JSON数据结构的任务编排,参数设计和实现
    • 急停功能实现,std::condition_variable

理论知识点

  • 关节空间,笛卡尔空间,正解,逆解,关节运动,直线运动,基底坐标系,末端坐标系,目标坐标系,世界坐标系,姿态,旋转向量,轴角,欧拉角,四元数,奇异点,奇异位置
  • 工厂模式
  • tcp/ip,http,websocket,REST ful,socket套接字,三次握手,四次挥手,大端字节序,小端字节序,状态机,同步编程,异步编程,线程池,静态文件托管,http文件上传和下载
  • 面向对象编程思想,封装,继承,多态,静态多态,动态多态,lambda表达式,智能指针,RAII思想,统一初始化,移动语义,互斥锁,读写锁,标准模板库,std::string, std::vector,std::map,std::thread, std::condition_variable

参考资料

  • 《机器人学导论》
  • 《应用机器人学-运动学-动力学与控制技术》
  • 《设计模式,可复用面向对象软件的基础》
  • 《UnixNetwork Programming》

简介

  • 数据结构相关笔记

  • 数据结构(data structure)是计算机中存储,组织数据的方式

  • 数据结构是一种具有一定逻辑关系,在计算机中应用某种数据结构,并且封装了相应操作的数据元素集合。它包含三方面的内容,逻辑关系,存储关系及操作。

  • 不同种类的数据结构适合于不同种类的应用,而部分甚至专门用于特定的作业任务。例如,计算机网络依赖于路由表运作,B树高度适用于数据库的封装。

  • 数据结构研究的内容:就是如何按一定的逻辑结构,把数据组织起来,并选择适当的存储表示方法把逻辑结构组织好的数据存储到计算机的存储器里。

常见的数据结构

  • 栈(stack): 栈是一种特殊的线性表,它只能在一个表的一个固定端进行数据节点的插入和删除操作
  • 队列(queue):队列和栈类似,也是一种特殊的线性表。和栈不同的是,队列只允许在表的一端进行插入操作,而在另一端进行删除操作
  • 数组(array):数据是一种聚合数据类型,它是将具有相同相同类型的若干变量有序的组织在一起的集合。
  • 链表(linked list):链表是一种数据元素按照链式存储结构进行存储的数据结构,这种存储结构具有在物理上存在非连续的特点。
  • 树(tree):树是典型的非线性结构,它是包括,2 个结点的有穷集合 K
  • 图(graph):图是另一种非线性数据结构。在图结构中,数据结点一般称为顶点,而边是顶点的有序偶对。
  • 堆(heap):堆是一种特殊的树形数据结构,一般讨论的堆都是二叉堆。
  • 散列表(hash table):散列表源自于散列函数(Hash function),其思想是如果在结构中存在关键字和T相等的记录,那么必定在F(T)的存储位置可以找到该记录,这样就可以不用进行比较操作而直接取得所查记录。

简介

  • 数据结构研究的内容:就是如何按一定的逻辑结构,把数据组织起来,并选择适当的存储表示方法把逻辑结构组织好的数据存储到计算机的存储器里。
  • 算法研究的目的是为了更有效的处理数据,提高数据运算效率。数据的运算是定义在数据的逻辑结构上,但是运算的具体实现要在存储结构上进行。一般有以下几种常用运算
    • 检索:检索就是在数据结构里查找满足一定条件的节点。一般是给定一个某字段的值,找具有该字段的节点
    • 插入:往数据结构中增加新的节点
    • 删除:把指定的节点从数据结构中去掉
    • 更新:改变指定节点的一个或者多个字段的值
    • 排序:把节点按某种指定的顺序重新排列。例如递增或者递减

简介

  • os模块相关笔记

python3 os模块 详解

os模块是Python中用于与操作系统进行交互的标准库之一。它提供了许多函数来执行文件和目录管理,处理文件路径,以及与操作系统交互的其他功能。下面是对os模块的一些主要功能的详解:

文件和目录操作

  1. 创建目录

    • os.mkdir(path): 创建单级目录。
    • os.makedirs(path): 递归创建多级目录。
  2. 删除目录

    • os.rmdir(path): 删除指定目录。
    • os.removedirs(path): 递归删除目录,直到指定目录。
  3. 文件和目录存在性检查

    • os.path.exists(path): 检查文件或目录是否存在。
    • os.path.isfile(path): 检查给定路径是否是文件。
    • os.path.isdir(path): 检查给定路径是否是目录。
  4. 重命名和移动

    • os.rename(src, dst): 重命名文件或目录。
    • os.replace(src, dst): 替换文件或目录,如果目标已经存在。
  5. 列出目录内容

    • os.listdir(path): 返回目录中的所有文件和目录的列表。
  6. 删除文件

    • os.remove(path): 删除指定文件。

路径操作

  1. 连接路径

    • os.path.join(path1, path2, ...): 将多个路径组合成一个路径。
  2. 获取文件名和目录名

    • os.path.basename(path): 返回路径的基本名称(文件名或目录名)。
    • os.path.dirname(path): 返回路径的目录部分。
  3. 获取路径信息

    • os.path.abspath(path): 返回路径的绝对路径。
    • os.path.split(path): 将路径拆分为目录和文件名的元组。
    • os.path.splitext(path): 将路径拆分为文件名和扩展名的元组。
  4. 检查路径属性

    • os.path.isabs(path): 检查路径是否是绝对路径。
    • os.path.islink(path): 检查路径是否是符号链接。
    • os.path.realpath(path): 返回符号链接的绝对路径。

其他操作

  1. 执行系统命令

    • os.system(command): 在系统上执行命令。
  2. 获取环境变量

    • os.getenv(name): 获取环境变量的值。
    • os.putenv(name, value): 设置环境变量的值。
  3. 进程控制

    • os.getpid(): 获取当前进程的PID。
    • os.kill(pid, signal): 向指定PID的进程发送信号。
  4. 文件描述符操作

    • os.open(file, flags[, mode]): 打开文件并返回文件描述符。
    • os.close(fd): 关闭文件描述符。

这些只是os模块中的一部分功能,但覆盖了许多常见的文件和目录操作,以及与操作系统进行交互的基本操作。

VSCode 基础

vscode c_cpp_properties.json excludePath参数 详解

在Visual Studio Code中,c_cpp_properties.json文件是用于配置C/C++扩展的解析设置的文件。在该文件中,excludePath参数用于指定应该在解析期间排除的目录。以下是对excludePath参数的详细解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"configurations": [
{
"name": "My Configuration",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "gcc-x64",
"excludePath": [
"${workspaceFolder}/path/to/excluded_directory",
"${workspaceFolder}/another/excluded_directory/**/*.cpp"
]
}
],
"version": 4
}
  1. ${workspaceFolder}: 这是一个变量,表示当前工作区的根目录。${workspaceFolder}/**表示将包括工作区中的所有文件和子目录。

  2. excludePath数组: 用于指定要在解析期间排除的目录。可以指定一个或多个目录,并使用相对于${workspaceFolder}的路径。在上面的示例中,两个目录都被排除了。

    • ${workspaceFolder}/path/to/excluded_directory: 表示要排除的第一个目录。
    • ${workspaceFolder}/another/excluded_directory/**/*.cpp: 使用通配符**表示所有子目录和其中的所有.cpp文件都应该被排除。
  3. 注意事项:

    • 在配置excludePath时,确保使用正确的相对路径,并确保路径是以${workspaceFolder}为基础的。
    • 你可以使用通配符**来匹配任意目录或文件。在示例中,/**/*.cpp表示匹配任意子目录下的所有.cpp文件。
    • 更改完成后,需要重启Visual Studio Code以使更改生效。

通过使用excludePath参数,你可以控制C/C++扩展在解析代码时忽略特定的目录,这对于排除不需要进行代码分析的目录非常有用。

解决cpptools high cpu问题

  • 在VScode菜单栏文件->首选项->设置 搜索C_Cpp.intelliSenseCacheSize,修改默认的5120为512

调试模式 设置环境变量

在Visual Studio Code (VSCode) 中,launch.json 文件用于配置调试器的启动选项。当您在VSCode中使用C++进行调试时,可以使用 launch.json 文件设置环境变量以定制调试过程。

以下是如何在 launch.json 文件中设置环境变量的步骤:

  1. 打开 VSCode,并在您的 C++ 项目文件夹中找到或创建 launch.json 文件。通常,该文件位于 .vscode 文件夹中。

  2. configurations 字段中添加一个调试配置。如果该字段为空,请复制以下 JSON 代码并粘贴到 launch.json 文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"version": "0.2.0",
"configurations": [
{
"name": "C++ Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/<your_executable>",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true
}
]
}
  1. 在上面的代码中,environment 字段用于设置环境变量。您可以将需要的环境变量添加到该字段中。每个环境变量都以键值对的形式表示,键和值之间使用冒号分隔。例如,如果要设置名为 MY_ENV_VAR 的环境变量,可以添加如下配置:
1
2
3
4
5
6
"environment": [
{
"name": "MY_ENV_VAR",
"value": "your_value"
}
]
  1. 保存 launch.json 文件。

  2. 在 VSCode 中打开您的 C++ 源代码文件,并在需要调试的行上设置断点。

  3. 单击 VSCode 左侧的调试图标(虫子图标),然后点击绿色的“启动调试”按钮。调试器将启动,并在设置的断点处停止。

  4. 如果有设置环境变量,它们将在调试过程中生效,您可以在调试过程中使用它们。

请注意:

  • 有些调试器可能不支持在 launch.json 文件中设置环境变量。确保您使用的调试器支持此功能。
  • launch.json 文件中设置的环境变量仅对该特定的调试配置生效。如果您有多个调试配置,每个配置可能需要不同的环境变量设置。

以上步骤是为了在 VSCode 中通过 launch.json 文件设置 C++ 调试的环境变量。如果您在调试过程中遇到问题,请确保配置正确,并查看调试器的文档以获取更多帮助。

自动换行

  • word wrap

VScode extensions xhr:failure

  • setting->details->Data&Time->Automatic Time Zone
    • open

下载

  • 首先,在官网找到需要下载的文件,点击下载,并将下载连接复制下来,例如:

    • https://az764295.vo.msecnd.net/stable/97dec172d3256f8ca4bfb2143f3f76b503ca0534/code_1.74.3-1673284829_amd64.deb
  • 然后,将az764295.vo.msecnd.net替换为vscode.cdn.azure.cn,例如:

    • https://vscode.cdn.azure.cn/stable/97dec172d3256f8ca4bfb2143f3f76b503ca0534/code_1.74.3-1673284829_amd64.deb
  • 这就是国内的镜像

使用root用户打开vscode

  • 背景:

    • 在远程调试机械臂的时候,需要使用到root权限来运行程序,所以在调试的时候需要使用到root权限
  • 方法:

    • 示例:code --no-sandbox --disable-gpu-sandbox --user-data-dir=".vscode-root"

VSCode 是什么

  • VSCode 是什么,VS Code的全称是Visual Studio Code,但这全名实在是太长了,很多用户喜欢叫它VS Code。说起VS Code,官方定义它是一个免费的、开源的跨平台编辑器。之所以强调“编辑器”,我想是因为 VS Code 并无意成为一个全尺寸的集成开发环境,也就是IDE

  • 很多人都把编辑器等同于IDE,其实从专业角度来讲并非这样。IDE 更为关注开箱即用的编程体验、对代码往往有很好的智能理解,同时侧重于工程项目,为代码调试、测试、工作流等都有图形化界面的支持,因此相对笨重,Java程序员常用的Eclipse定位就是IDE;而编辑器则相对更轻量,侧重于文件或者文件夹,语言和工作流的支持更丰富和自由,VS Code 把自己定位在编辑器这个方向上,但又不完全局限于此。

  • 要理解VS Code代码编辑器的设计思路,就需要先看看VS Code的发展轨迹。

  • 从我的角度看,不管你是学习编程语言,还是框架、编辑器,都应该先去看看它的来龙去脉,了解它们是怎么发展而来的,曾经遇到了什么问题,又是怎么解决的,这些信息都便于你从大局上提高对事情本质的认识

  • VSCode 发展历史:https://geek-docs.com/vscode/vscode-tutorials/what-is-vscode.html

VSCode的学习路线

  • 简短地了解了 VS Code 的历史后,如果你也认同它的设计哲学和使命,你肯定还想知道该如何把 VS Code 的这一套转化为自己的内力。我在第一讲 “学编辑器,到底应该‘学’什么?” 里讲过编辑器学习的通用办法,在 VS Code 身上也是适用的。你可以按照以下三个步骤来逐步掌握 VS Code。

    • 核心编辑器的使用。VS Code 有一套自己的快捷键,你可以通过快捷键的学习了解核心编辑器所支持的功能。同时, VS Code 允许自定义快捷键的映射,如果你有自己熟悉的一套快捷键操作,也可以无缝地在 VS Code 上使用。除了快捷键,VS Code 对鼠标操作、多光标、搜索都有完备的支持;在编程语言的支持上面,VS Code 也向 IDE 看齐,自动补全、代码片段等一应俱全。掌握了核心编辑器,VS Code 就能够胜任你的日常通用编辑器。
    • 工作台、工作区的使用。VS Code 中除了编辑器区域,还有很多其他的功能,像是资源管理器、跨文件搜索、插件管理等,它们一起组成了统一的界面,我们称之为工作台。这个工作台的设计,代表了 VS Code 对工作流的选择。内置的软件版本管理,终端模拟器,调试器等,掌握这些 VS Code “钦定”的工具,进一步提升工作效率。
    • VS Code 定制和插件开发。作为一个百万级别用户量的工具,很多功能的默认设置不可能满足每个人或者每个工作场景,你可以学习如何定制 VS Code 的各个部件,不能永远按部就班;对于 VS Code 没有实现的功能,还可以学习一下如何使用 JavaScript 书写插件,把自己的想法,变成工具的一部分。
  • 通过这三个步骤,你在使用 VS Code 时就能够“随心所欲”了。除此之外,我也建议你关注 VS Code 每月的发布更新日志,官方团队会详细讲解每个版本新增的功能。VS Code 的官方博客也非常值得订阅,团队成员会经常分享开发过程的心得感悟,算得上是最前沿的技术分享。

VSCode入门

  • 主要讲一下“学习”区域的三个功能:命令面板、界面概览和交互式演习场

命令面板

  • 首先来看命令面板,它是 VS Code 快捷键的主要交互界面,你可以通过 F1 或者“Cmd+Shift+P ”(Windows 上是 “Ctrl+Shift+P”) 打开。这里提醒一下,如无特殊说明,我在这个专栏里默认基于macOS平台进行讲解,但也会本着为你提供方便的原则,同时给出Windows或Linux平台下的操作说明。通过编辑器来实现高效编程的思路是一致的,这和具体的使用平台无关,所以你大可不必为此担心。
  • 你可以在命令面板中快速搜索命令并且执行。如果你的 VS Code 是简体中文版,那么你可以在命令面板里使用中文或者英文来搜索命令。VS Code 的绝大多数命令都可以在命令面板里搜到,所以熟练使用命令面板,你就可以摆脱鼠标,完全通过键盘操作来完成全部编码工作。

界面概览

  • 第二个是界面概览,它展示了 VS Code 默认界面里的不同部件的位置、名称和快捷键。VS Code 强调无鼠标操作,但是对于初学者而言快捷键的记忆是个麻烦,这个界面恰好可以帮助你渡过最初的不适应阶段。

交互式演习场

  • 第三个是交互式演习场,打开这个界面,你会看到一个全英文的初学者教程,其中通过各种交互示例给出了 VS Code 的核心功能,展示了一些高级代码编辑功能的使用,每个功能都会有一个代码片段和编辑器供你实时使用。

命令行的使用

  • 如果你是 Windows用户,安装并重启系统后,你就可以在命令行中使用 code 或者 code-insiders了,如果你希望立刻而不是等待重启后使用,可以将 VS Code 的安装目录添加到系统环境变量 PATH中, Windows 64 位下的 VS Code 安装路径是 C:\Program FIles\Microsoft VS Code下。

  • 如果你希望使用已经打开的窗口来打开文件,可以在 code 命令后添加参数 -r来进行窗口的复用。

  • 你也可以使用参数 -g <file:line[:character]> 打开文件,然后滚动到文件中某个特定的行和列,比如:

    • 输入 code -r -g package.json:128命令,你就可以打开 package.json 这个文件,然后自动跳转到 128 行。
    • 这个命令可以方便你从终端里快速地在 VS Code 里打开一个文件进行预览,一个特别常见的例子就是当我们使用脚本执行某个命令,这个命令告诉我们某个文件的某一行出现了错误,我们就能够快速定位了。
  • VS Code 也可以用来比较两个文件的内容,你只需使用 -d参数,并传入两个文件路径,比如:

    • 输入 code -r -d a.txt b.txt命令,就可以比较a.txtb.txt两个文件的内容了。
    • 有了这个命令,你就可以既使用命令行运行脚本,也可以借助 VS Code 的图形化界面进行文件内容的对比了。
  • VS Code 命令行除了支持打开磁盘上的文件以外,也接受来自管道中的数据。这样你就可以将原本在命令行中展示的内容,实时地展示在 VS Code 里,然后在编辑器中搜索和修改。比如,你可以把当前目录下所有的文件名都展示在编辑器里,此时只需使用ls | code -命令。

VSCode 键盘操作

  • VSCode 键盘操作,做到双手不离键盘,今天先来谈一谈核心的键盘操作:光标的移动、文本的选择、文本的删除,以及如何为编辑器命令绑定快捷键。

光标移动

  • 移动光标最常用的就是方向键,但是方向键每次只能把光标移动一个位置,可以说是一种相对低效的方式。

  • 首先是针对单词的光标移动。这个你应该比较熟悉,绝大多数原生的编辑应用和文本框都支持。这也是我自己最常用的一组快捷键。

    • 下面这张图显示,第一行代码中的第一个单词是 function,一共8个字符,光标的位置在第五个字符 t 的后面。当你想把光标直接移动到整个单词,也就是 function 的前面,你只需按下 Option(Windows 上是 Ctrl 键)和左方向键。相反,如果要把光标移动到单词的末尾,只需要按下 Option 和右方向键就好了。
    • 我们都知道,一直按着方向键,光标就可以不停地,一个字符一个字符地在文档中移动。但如果你同时按住 Option 和方向键,那么光标移动的颗粒度就变成了单词,你就可以在文档中以单词为单位不停地移动光标了
  • 第二种方式是把光标移动到行首或者行末。比如第一行代码是 function foo() {,你只需按住 Cmd + 左方向键(Windows 上是 Home 键),就可以把光标移动到了这行的第一列;而如果你按住 Cmd 和右方向键(Windows 上是 End 键),光标就会被移动到 { 的后面。

  • 接下来一种是对于代码块的光标移动。很多编程语言都使用花括号将代码块包裹起来,比如 if、for 语句等,你很可能会希望通过一个快捷键,就能实现在代码块的始末快速跳转。比如在这5行代码示例中,第一行到第三行代码是函数 foo 的定义,由一对花括号包裹起来,当你把光标放在花括号上时,只需按下 Cmd + Shift + \(Windows 上是 Ctrl + Shift + \),就可以在这对花括号之间跳转。

  • 最后一种基础的光标操作就是移动到文档的第一行或者最后一行,你只需按下 Cmd 和上下方向键即可(Windows 上是 Ctrl + Home/End 键)。

文本选择

  • 掌握了上面的快捷键之后,你还可以非常轻松地掌握文本选择的操作。因为对于基于单词、行和整个文档的光标操作,你只需要多按一个 Shift 键,就可以在移动光标的同时选中其中的文本

删除操作

  • 比如你想把当前行中光标之前的文本全部删除,就可以先选中这段文本(Windows/Linux: Home + Shift,macOS: Cmd + Left + Shift ),然后再按删除键。不过对于频繁使用的删除操作,你肯定希望单次操作就可以完成任务,而不是重复地选择文本然后删除,那么你需要记住下面几个命令。

  • 假设你把光标放在第二行代码的中间位置,然后按下 Cmd 和 Backspace(MacOS上就是“fn + delete”的组合,Windows 上未绑定快捷键,可以打开命令面板运行“删除右侧所有内容”),就能够把第二行代码光标后(右侧)的字符全部删掉。

  • 按下 Cmd 和 Delete 键则是删除当前行中光标前(左侧)的所有内容(Windows 上未绑定快捷键,可以打开命令面板运行“删除左侧所有内容”)

  • 删除单词内的字符与此类似。假设把光标放在第一行第四个字符 c 的后面。Option 加左方向键把光标移动到 function 这个单词的开头,Option加左方向键再加 Shift 即可选中 func 这四个字符,而Option 加 Delete 则会删除 func 这四个字符。这里你可能看出来了,这些快捷键共同的是 Option 键,然后通过按下 Shift 或者 Delete 键,来达到不同的效果。

  • 相反地,Option 加 Backspace(MacOS上就是“fn + delete”的组合) 则会删除 function 的后四个字符 tion。

自定义快捷键

  • 前面我们提到,VS Code 内置了很多的命令,但是并没有为每个命令都提供一个快捷键,毕竟快捷键的组合总是有限的。不过 VS Code 提供了快捷键的修改和自定义功能,这样你就可以根据自己的使用习惯,给自己常用的命令指定顺手的快捷键。

  • 首先你可以打开命令面板(你还记得它的快捷键不?),搜索“打开键盘快捷方式”然后执行,这时你将看到相对应的界面。

  • 然后通过搜索找到你希望修改快捷键的命令,双击,接下来你只要按下你期望的快捷键,最后按下回车键就可以了。

  • 比如,你可以搜索“选择括号内所有内容”,双击,按下”Cmd + Shift + ]”,然后按下回车,这个快捷键就绑定上了。

  • VS Code 的快捷键修改界面已经考虑到了这一点,你可以在搜索框内搜索你使用的快捷键,然后就可以看到这个快捷键当前对应的命令是哪个。

VSCode 代码行编辑

  • 要删掉一行代码,你可以选中它,然后再按 Delete 键。不过还有一个快捷键,那就是直接按下 “ Cmd + Shift + K ” (Windows 上是 “Ctrl + Shift + K”),当前代码行就可以被删除了。

  • 如果你只是想要剪切这行代码,那么你直接按下 “ Cmd + x ” (Windows 上是 “Ctrl + x”) 即可。

  • 我想你肯定很清楚,“Enter” 键的基础作用是能在编辑器里光标所在的位置添加一个换行符。但是很多时候你可能并不是单纯地要将一行分成两段,而是希望在这行的下面或者上面开始一段新的代码。

  • 这个功能对应的快捷键非常好记,它跟 “Enter”键十分接近。当你想在当前行的下面新开始一行时,你只需按下 “Cmd + Enter” (Windows 上是 “Ctrl + Enter”);而当你想在当前行的上面新开始一行时,你只要按下 “Cmd + Shift + Enter” (Windows 上是 “Ctrl + Shift + Enter”)就行了

  • 当你想移动一段代码时,一般你可能会分三步走:先选中,再剪切,最后粘贴。不过我更喜欢的是按住 “Option + 上下方向键”(Windows中就是“Alt + 上下方向键”) ,将当前行,或者当前选中的几行代码,在编辑器里上下移动。

  • 如果你同时按住 “Shift” 键的话,也就是 “Option + Shift + 上下方向键”(Windows中就是“Alt + shift + 上下方向键”),那就可以复制这几行,然后粘贴到当前行的上面或者下面。

  • 另外,你在尝试“Option + 上下方向键”这个快捷键“上下移动”时,可能也发现了,当你把一段代码移动到花括号里面或者外面时,代码前的制表符或者空格的数量会自动发生改变,这样你就不需要移动完代码后再调整了。

VSCode 撤销光标移动

  • VSCode 撤销光标移动,撤销光标的移动和选择。有的时候你移动完光标之后,又希望把光标回退到上一个位置,这时你只需按下 “Cmd + U”(Windows 上是 Ctrl + U),就可以撤销这一次光标的移动。

VSCode 行排序

  • VSCode 行排序。无论是你在写代码,还是写 Markdown,你都可以把代码行按照字母序进行重新排序。不过这个命令比较小众,VS Code 并没有给这个命令指定快捷键,你可以调出命令面板,然后搜索 “按升序排列行” 或者 “按降序排列行” 命令执行。

VSCode 合并代码行

  • VSCode 合并代码行。有的时候你可能会为了避免代码看起来过于冗余,就会把比较短小的几行代码合并到一行里面去。这时,你只需要按下 “ Ctrl + j ” (Windows 上未绑定快捷键,可以打开命令面板,搜索 ”合并行“)就可以了,而不需要不断地调整光标、删除换行符。

VSCode 调整字符大小写

  • VSCode 调整字符大小写,我估计这个你会经常用到。你可以选中一串字符,然后在命令面板里运行“转换为大写”或 “转换为小写”, 来变换字符的大小写。

VSCode 调换字符位置

  • VSCode 调换字符的位置。你可以按下 “Ctrl + t” (Windows 上未绑定快捷键,可以打开命令面板,搜索 ”转置游标处的字符“) 来把当前光标前后的字符调换位置。

VSCode 代码缩进

  • VSCode 代码缩进,有的时候,你会觉得代码格式化太重了,需要的可能只是把代码里的缩进调整一下。这时你可以打开命令面板(快捷键“Cmd + Shift + P”),搜索 “缩进”,然后使用 “重新缩进行” 将整个文档的缩进进行调整,但更多时候,你只需要运行 “重新缩进选中行” 来调整部分选中代码行的缩进。

VSCode 代码格式化快捷键

  • VSCode 代码格式化快捷键,我们平常在做自己的小项目或者随便写一些脚本的时候,可能不会太在意代码的格式。不过一旦开始团队合作,整个项目组则会选择同一个代码风格和格式以有效降低协同成本。所以定期对自己写的代码进行格式化是个很好的习惯。

  • 你可以按下 “Option + Shift + F” (Windows 上是 Alt + Shift + F)来对整个文档进行格式化,VS Code 也会根据你当前的语言,选择相关的插件。当然,前提条件是你已经安装了相关插件。

  • 你也可以选中一段代码,然后按下 “Cmd + K Cmd + F” (Windows 上是 Ctrl + K Ctrl + F),这样只有这段被选中的代码才会被格式化。

VSCode 添加代码注释

  • VSCode 添加代码注释,你在调试代码时,肯定经常需要临时地把一些代码注释掉。如果你要将一行代码注释掉,你只需按下 Cmd + / (Windows 上时 Ctrl + /)。如果你需要把一整段代码注释掉,按下 Option + Shift + A即可。

VSCode 自动补全

  • VS Code自动补全,VS Code 当中的自动补全内容,其实是由语言服务来提供的。本文介绍VS Code自动补全功能和VS Code自动补全设置。

  • VS Code 为编程语言工作者提供了统一的 API ,即 Language Server Protocol,每种语言都能够通过实现这个 API 在 VS Code 上得到类似 IDE 的开发体验,而各个语言根据这个 API 实现的服务,就被称为语言服务。

  • 语言服务会根据当前的项目、当前的文件,以及光标所在的位置,为我们提供一个建议列表。这个列表包含了在当前光标位置下我们可能会输入的代码。当我们不断地输入字符,VS Code 就会根据当前输入的字符,在这个列表进行过滤。

  • 如果我们偶尔觉得这个自动补全窗口是多余的,希望暂时不看到它,可以按下 Escape 键将其隐藏。后续如果希望再次看到这个窗口,除了通过打字来将其调出以外,我们还可以按下 “Ctrl + 空格键”来手动地调出建议列表。

  • 刚才我们提到,VS Code 会根据我们输入的字符在这个建议列表里进行过滤。同时,这个过滤是允许我们犯一点小错误的,比如打字特别快的时候少打一个字母,VS Code 也能处理这个情况。比如在下面的动图里,我想使用 console 里的 debug 函数,但是我只打了 db 两个字母,建议列表依然为我提供了 debug 这个选项。

  • 上面的这几个窗口,它们都是通过我们输入的内容自动触发的,也就是说,编程语言决定了我们什么时候看到什么内容。虽然我们可以通过快捷键将其快速地关闭和唤出,但是有的时候自动补全窗口出现得过于频繁,也是会影响我们的编程体验的,毕竟悬浮窗口会遮盖一部分代码,影响我们的阅读。

  • 不过,我们可以通过几个设置,控制自动补全窗口出现的频率和方式,甚至这个窗口的大小。

  • 首先我们可以通过设置 “editor.quickSuggestions” 来决定在什么语境下自动补全窗口会被唤出。默认设置如下:

    1
    2
    3
    4
    5
    "editor.quickSuggestions": {
    "other": true,
    "comments": false,
    "strings": false
    }
    • 这个配置有三个选项:other、comments和strings。其中,comments 就是代码注释,strings 就是指字符串。默认情况下,当光标在代码注释或者字符串里,自动补全窗口就不会被自动唤出了。但如果你希望这个窗口永远不被自动唤出,那么你就需要将“other” 也改为 “false”。
  • 这时你可能会问了,如果关闭了这个设置,我想看到自动补全该怎么办呢?不用担心,当你按下 “Ctrl + 空格键” 之后,这个窗口依然会被打开,不管设置是关闭还是开启的状态。看到这个设置,你肯定也就明白了,为什么默认情况下你在写注释的时候没有代码自动补全的提示了吧。

  • 参数预览窗口也是一样的,你可以通过参数 “editor.parameterHints.enabled” 将其关闭。当你觉得自己需要看一看参数预览时,按下快捷键或者通过命令面板就能够将其打开了。

  • 上面的这个设置决定“是与否”的问题,但你也可以控制自动补全窗口出现的时间。自动补全窗口监听文件内容的变化,当你停止输入时,它就会试着给你提供建议。但是有的时候你打字稍微快一些,自动补全窗口才刚刚出现,你就输入了更多的内容,紧接着代码服务就要重新计算并提供建议了。如果你希望减少这种不必要的提示,可以增大设置 “editor.quickSuggestionsDelay” 的值,这样在你输入完代码后,自动补全窗口就会多等一会儿,然后再跳出来。

  • 其他几个自动补全的设置,你可以在设置里搜一搜 “editor.suggest”,自己修改玩一玩。

  • 上面提到的几个功能,它们都依托于语言服务来提供内容。但是有的时候,语言服务并不完美。编辑器于是提供了一种相对 “笨” 一些的提示,那就是基于单词的提示。编辑器通过分析当前的文件里的内容,进行简单的正则表达式匹配,给我们建议已经出现过的单词。

VSCode 文本选择

  • 最简单的方式,也是我们每个人最熟悉的方式,就是按住鼠标左键,然后拖动鼠标,直到选中所有我们想要选择的文字为止,再松开鼠标即可。

  • 那是不是说鼠标用户要完成类似的操作,就只能“一点、二拖、三松手”呢?当然不是,VS Code 其实给鼠标也配备了类似的快捷键。

  • 在VS Code中:

    • 你单击鼠标左键就可以把光标移动到相应的位置。
    • 而双击鼠标左键,则会将当前光标下的单词选中。
    • 连续三次按下鼠标左键,则会选中当前这一行代码。
    • 最后是连续四次按下鼠标左键,则会选中整个文档。
  • 到这里你可能会问,如果我想要使用鼠标,选中其中的多行代码该怎么办?VS Code也考虑到了这个情况,在编辑器的最左边,显示的是每一行的行号。如果你单击行号,就能够直接选中这一行。如果你在某个行号上按下鼠标,然后上下移动,则能够选中多行代码。

VSCode 快速预览

  • VS Code快速预览是指,有的时候,当我们看到一个建议列表里的某个函数名,我们可能并不能够立刻想起它的作用是什么,它的参数定义是什么样的。
  • 这时候我们可以单击当前这一项建议的最右侧的蓝色图标。
  • 点击这个图标后,建议列表旁边就有出现一个快速预览的窗口,而这个窗口里面呈现的就是这个函数的定义。具体如下图:
  • 除了使用鼠标键外,我们还可以使用 “Ctrl+空格键”组合键来快速调出这个快速预览窗口。

VSCode 参数预览

  • VS Code参数预览,当我们从建议列表选择了一个函数,然后输入括号,准备开始输入参数时,我们会看到一个参数预览的悬浮框。通过这个参数预览的窗口,我们可以知道这个函数可以传入哪些参数,它们的参数类型又是什么样的。
  • 同样的,隐藏这个窗口的快捷键也是 Escape。如果你想再次将其调出的话,需要按下 “Cmd + Shift + Space” (Windows 上是 Ctrl + Shift + Space)。

VSCode 重构

  • 当我们想要修改一个函数或者变量的名字的时候,我们只需要把光标放到函数或者变量名上,然后按下F2,这样这个函数或者变量出现的地方就都会被修改

  • 这个操作并不是一个粗暴的搜索关键词并替换,在上面的动图中你可以看到,最后一行代码里有个 bar3函数调用,但当我们去重命名 bar这个函数时,bar3并没有受到影响。

  • 除了重命名外,另一个常用的重构的操作就是把一段长代码抽取出来转成一个单独的函数。在VS Code中,我们只需选中那段代码,点击黄色的灯泡图标,然后选择对应的重构操作即可。

  • 要注意的是,并不是每个语言服务都支持重构的操作。如果你选中一段代码后,但没有看到那个黄色的灯泡图标,那么也就是说你使用的这门语言可能还没有支持快速重构。

VSCode 文本编辑

  • VS Code文本编辑,在 VS Code中,我们除了能够使用鼠标来选择文本以外,还能够使用鼠标对文本进行一定程度的修改,我们把它称为拖放功能(drag and drop)。

  • 比如在今天的示例代码中,我们选中 bar 这个函数,然后将鼠标移到这段选中的代码之上,按下鼠标左键不松开。这时你可以看到,鼠标指针已经从一条竖线,变成了一个箭头。这时候我们移动鼠标的话,就可以把这段文本拖拽到我们想要的位置。

  • 在移动的过程当中,我们能够在编辑器中看到一个由虚线构成的光标,当我们松开鼠标左键的时候,这段文本就会被移动到这个虚拟的光标所在的位置。

  • 如果我们在拖拽这段文本的同时,按下 Option 键(Windows 上是 Ctrl 键),鼠标指针上会多一个加号,这时候我们再移动鼠标或虚拟光标至我们想要的位置,然后当我们松开鼠标左键的时候,这段文本将会被复制粘贴到虚拟光标所在的位置,也就是我们既定的目标位置。

  • 你看,在移动鼠标的过程中,多按了个 Option 键(Windows 上是 Ctrl 键),操作结果就由原来的“剪切+粘贴”变为“复制+粘贴”了。

VSCode 多光标

  • VSCode 多光标特性,在我们的日常编码过程中,有很多工作,它本身就是具有“重复”属性的。比如你需要把多个单词的第一个字母从小写变成大写,这种跟业务逻辑相关的重复性操作,编辑器很难为它们一个个单独做优化。

  • 而 VS Code 的多光标特性其实就是用来解决这类问题的。当你在一个文本框或者某个输入框里打入字符时,会有一个竖线来显示你将要输入文字的位置,这就是“光标”。顾名思义,多光标其实就是多个输入位置,这里你可以脑补下多个竖线的场景。

  • 多光标特性允许你在输入框的多个位置创建光标,这样你就可以在多个不同的位置同时输入文字或者执行其他操作

  • “Cmd + D” 这个命令的作用是,第一次按下时,它会选中光标附近的单词;第二次按下时,它会找到这个单词第二次出现的位置,创建一个新的光标,并且选中它。这样只需要按下三次,你就选中了所有的“5”。这个时候你再按下 “右方向键”,输入“px”,即可完成任务。

  • 接下来讲讲第二种,是跟代码行批量处理有关,也还是用的前面的代码。首先你选择多行代码,然后按下 “Option + Shift + i” (Windows 上是 Alt + Shift + i),这样操作的结果是:每一行的最后都会创建一个新的光标。

  • 不过,VS Code 中还有一个更加便捷的鼠标创建多光标的方式。当然,这首先要求你的鼠标拥有中键。你只需按下鼠标中键,然后对着一段文档拖出一个框,在这个框中的代码就都被选中了,而且每一行被选中的代码,都拥有一个独立的光标。

VSCode 代码跳转和链接

  • 我们还是把鼠标移动到示例代码的第五行 foo 上,然后按下 Cmd 键,这时候 foo下面出现了一个下划线。然后当我们按下鼠标左键,就跳转到了 foo函数的定义处。

VSCode 文件跳转

  • 在VS Code中,解决这个问题的第一个方法,就是按下 “Ctrl+Tab”,然后继续按着 “Ctrl”键但是松开 “Tab” 键,这样你就可以打开一个文件列表,这个列表罗列了当前打开的所有文件。接下来,你可以通过按下 “Tab”键在这个列表里跳转,选择你想要打开的文件。最后选到你想打开的文件后,松开 “Ctrl” 键,这个文件就被打开了
  • 还好,VS Code 在命令面板里提供了一种支持搜索的文件跳转方式。当你按下 “Cmd + P” (Windows 上是 Ctrl + P)时,就会跳出一个最近打开文件的列表,同时在列表的顶部还有一个搜索框。
  • 看到这里想必你应该明白了,你可以使用这个搜索框来快速地找到你想要的文件,然后按下 “Enter” 键直接打开,这整个过程简单而且顺畅。

VSCode 行跳转

  • VS Code也提供了一种极为简单的方式来支持行跳转,你只需要按下 “Ctrl + g”,紧接着编辑器就会出现一个输入框
  • 如果你想跳转到某个文件的某一行,你只需要先按下 “Cmd + P”,输入文件名,然后在这之后加上 “:”和指定行号即可。跳转到指定文件的指定行数

VSCode 符号跳转

  • VS Code符号跳转,文件跳转和行跳转,是代码跳转的基本操作,也是日常编码中的高频操作。不过有的时候,你可能会希望能够立刻跳转到文件里的类定义,或者函数定义的位置。为了支持这种跳转,VS Code 提供了一套 API 给语言服务插件,它们可以分析代码,告诉 VS Code 项目或者文件里有哪些类、哪些函数或者标识符(我们把这些统称为符号)。

  • 如果要在一个文件里的符号之间跳转,你只需按下 “Cmd + Shift + O” (Windows 上是 Ctrl + Shift + O),就能够看到当前文件里的所有符号。

  • 使用方向键,或者搜索,找到你想要的符号后,按下回车,就能够立刻跳转到那个符号的位置。如下图所示:通过符号功能跳转到指定的代码位置

  • 请注意,在按下 “Cmd + Shift +O”后,输入框里有一个 “@”符号,这个符号在这里的意义,我会在后面的章节里去介绍,你可以先留个心眼。这时,如果你输入 “:”,就可以将当前文件的所有符号,进行分类,这样搜索符号也就更加方便。

  • 有些语言除了提供单个文件里的符号,还支持在多个文件里进行符号跳转。比如在 VS Code 里,如果你打开了多个 JavaScript 文件,就可以按下 “Cmd + T” (Windows 上是 Ctrl + T),搜索这些文件里的符号。

  • 通过“Cmd + T”,搜索多个文件的符号

VSCode 定义和实现间跳转

  • F12跳转到函数定义的位置
  • 也可以按下 “Cmd + F12” (Windows 上是 Ctrl + F12),跳转到函数的实现的位置。

VSCode 跳转到引用的地方

  • VS Code引用跳转,很多时候,除了要知道一个函数或者类的定义和实现以外,你可能还希望知道它们被谁引用了,以及在哪里被引用了。这时你只需要将光标移动到函数或者类上面,然后按下 “Shift + F12”,VS Code 就会打开一个引用列表和一个内嵌的编辑器。在这个引用列表里,你选中某个引用,VS Code 就会把这个引用附近的代码展示在这个内嵌的编辑器里。

  • Shift+ F12打开函数引用预览

VSCode 代码片段

  • VSCode代码片段,有的时候,我们经常输入的代码是业务强相关的,语言服务没法做出优化;或者是一些我们经常使用的定式,比如循环语句、创建一个新的类或者一个 UI 控件,我们经常写类似的代码,只不过每次都要做细微的修改。对于这些代码,我们可以将它们抽象成模板,保存起来,等下次要使用的时候直接调用即可。

  • 代码片段是对常用代码的一个抽象,它保留了大部分不变的代码,然后把需要经常变动的部分,换成变量,这样等下次调用它的时候,只需要把这些变量换成我们需要的就可以了

  • 首先,我们打开命令面板,搜索“配置用户代码片段”(Configure User Snippets)并且执行。这时候我们会看到一个列表,让我们选择语言。这里我们依然选择 JavaScript 作为我们的示例语言,不用担心,代码都是非常简单和易于理解的。命令面板,搜索“配置用户代码片段”并且执行

  • 选择完语言后,我们就能看到一个 JSON 文件被打开了,这个文件里的内容,现在都是被注释掉的。我们可以选中第七行到第十四行,按下 Cmd+ / 取消注释。

  • 在上面的例子里,这个代码片段的名字叫做 Print to console 。这个代码片段对象的值,也就是花括号里的代码,必须要包含 “prefix” 前缀和 “body” 内容这两个属性。同时,这个值还可以包含 “description” 描述这个属性,但这个属性不是必须的。

  • “prefix” 的作用是,当我们在编辑器里打出跟 “prefix” 一样的字符时,我们就能在建议列表里看到这个代码片段的选项,然后我们按下 Tab 键,就能够将这个代码片段的 “body” 里面的内容插入到编辑器里。如果这个代码片段有 “description” 这个属性的话,那么我们还能够在建议列表的快速查看窗口里看到这段 “description”。

  • 输入 log 即可看到 Print to console 代码片段,然后再按下回车或者 Tab 键,就能够将这个代码片段插入编辑器了。

VSCode 折叠代码快捷键

  • VSCode折叠代码快捷键,我们再来一起看一下有哪些折叠和展开代码的快捷键。首先是折叠和展开代码的两个快捷键。

  • 当我们按下 “Cmd + Option + 左方括号”(Windows 上是 Ctrl + Shift + 左方括号),当前光标所处的最内层的、可以被折叠的代码就会被折叠起来。请注意,我们在这里加了两个限制条件,“最内层”和“可以被折叠”。我们可以先用下面一个小例子来理解这两个条件。

VSCode 小地图

  • 如果你是在一个比较大的屏幕上工作,需要快速了解整个文件的全貌,并且还能靠鼠标快速地移动,那么这时小地图就很有用了。这个功能默认是打开的,所以你无需特别设置。这个使用起来比较简单,你可以像我在图中展示的那样试着打开一个较大的文件,感受一下它的妙处。

  • 很多游戏中也有类似的小地图功能,不知道你有没有似曾相识的感觉。

  • 除了控制小地图是否打开,编辑器还为我们提供了几个渲染的配置项。比如说,默认情况下,小地图会将每个字符都渲染出来。但是我们并不能真正地通过小地图来看代码,我们只是要看个大概结构罢了,那么我们可以打开命令面板,搜索“打开设置”(Open Settings),进入设置界面后,搜索 “editor.minimap.renderCharacters” ,找到后将其关闭,这样一来,所有的字符,都会被渲染成一个个小色块。

  • 同样的,我们还可以通过 “editor.minimap.maxColumn” 来控制小地图里每一行渲染多少个字符。很多时候我们只需看下每行代码前的缩进和前面的代码高亮,就能看出个大概来了。

VSCode 单文件搜索

  • VSCode单文件搜索,今天我们重新回到原点,来看一下如何使用编辑器自带的文本搜索功能,快速地穿梭于海量的代码之中。在我看来,一个功能丰富且快速的搜索,在很多情况下甚至会比语言服务还要来得有用。

  • 我们把光标放在编辑器当中,然后按下 “Cmd + F” (Windows 上是 Ctrl + F),就能够快速地调出搜索窗口(可能这个命令你早就发现了或者经常使用了)。当我们调出搜索窗口的时候,编辑器就会把当前光标所在位置的单词自动填充到搜索框中。与此同时,当前文件里和搜索关键词相同的单词都会被高亮出来。

  • 自动填充搜索关键词的好处在于,当我们按下 “Cmd +F” 搜索这个单词之后,我们还能够立刻通过回车键或者 “shift+回车键” 在所有搜索结果当中快速跳转。

  • 这里需要注意的事情是,当我们开始搜索的时候,光标已经被移动到了搜索框当中,如果在这时候我们继续打字的话,那原有的搜索关键词将会被修改。

  • 如果我们希望找到搜索结果后,接下来就直接修改编辑器中的内容,那么就得将光标重新移动到编辑器当中,听起来就挺不方便的,是不是?

  • 这种情况下,我们不妨换一个快捷键。首先我们将光标移动到我们想要搜索的单词处,然后按下 “Cmd + G” (Windows 上是 F3),此时我们同样调出了搜索框,但与前面 “Cmd +F ” 这个快捷键不同的是,这时光标依然是在编辑器当中,而不是在搜索框中。

  • 下面我们再一起来看下这个搜索框中都有哪些功能。

  • 当我们在搜索框中打字的时候,搜索操作是自动触发的,而无需我们再按下回车键去手动地执行搜索这个操作。

  • 除了搜索纯文本以外,搜索框还支持多种不同的搜索方式。比如,在搜索框的最右侧,就有三个配置按钮。

    • 第一个是大小写敏感。 这个很好理解,就是在文档中搜索关键词的时候,搜索的结果是否要跟关键词大小写完全一致。默认情况下,VS Code 的搜索是不区分大小写的,也就是说哪怕大小写不一样,也会算到搜索结果里去。但如果我们不想要这个特性,就可以点击这个按钮,或者按下 “Cmd+Option+C” (Windows 上是 Alt + C)来关闭它。
    • 第二个是全单词匹配。 有的时候我们搜索的单词恰好是别的某个单词中间的一部分,如果我们不希望这样的结果出现在搜索结果中,那么就可以点击这个按钮或按下 “Cmd+Option+W” (Windows 上是 Alt + W)来关闭它。
    • 第三个,就是正则表达式匹配了。 当我们点击这个按钮或按下 “Cmd + Option + R” (Windows 上是 Alt + R ),就能够打开正则表达式的支持,然后在搜索框中输入正则表达式来搜索。要注意的是,编辑器中的这个搜索框,它里面的正则表达式使用的是 JavaScript 的正则引擎。
  • 这三个功能的快捷键的配置,相信你已经看出其中的诀窍了,它们分别使用了 Case、Word 和 Regular Expression 的第一个字母作为快捷键的一部分,若你知道是这几个单词,那相信对应的快捷键你就不会容易忘了。

  • 我们可以先选中一段文本,然后按下 “Cmd + F” 调出搜索框,这之后点击这个按钮,就可以将这段文本的范围设置为接下来的搜索区域。然后当我们在输入框里输入关键字后,编辑器就只会在这个区域里进行搜索。

  • 上面我们提到的功能,都是 VS Code 的默认行为。但也有部分用户不喜欢搜索框的一部分行为,比如说自动填充搜索关键词。那你可以打开设置,搜索 “editor.find.seedSearchStringFromSelection” 来关闭它。

  • 也有个别用户觉得,如果选中了多行文本,那么当开始搜索时,应该自动地只在这几行代码里进行搜索。要达成这样的目的,你则需要打开设置 “editor.find.autoFindInSelection” 。

VSCode 单文件替换

  • VSCode单文件替换,在搜索到我们想要的结果之后,我们可以直接在文件中进行修改,也可以使用替换窗口进行批量替换。如果你在使用鼠标或者是触控板的话,只需按一下搜索窗口最左侧的箭头按钮即可打开替换框。
  • 替换框的后面,一共有两个按钮:第一个能够替换单个搜索结果,第二个则能够替换全部的搜索结果。它们对应的快捷键我就不多加赘述,我们只需把鼠标指针移动到它们上面,就能够看到了。
  • 我们也可以通过快捷键直接调出替换窗口。最常用的命令就是按下 “Cmd + Option + F”(Windows 上是 Ctrl + H)键,这样当前光标所在的单词就会被用作为搜索关键词,同时编辑器将光标移动到替换窗口中,我们只需直接输入想要替换的关键词就行了,是不是很便捷呢?
  • 当然,如果你在书写完替换文本后,觉得搜索关键词需要修改,那你可以按下 “Shift + Tab” 键将光标移动到上面的搜索输入框里。“Tab” 和 “Shift + Tab” 键能够帮助你在这两个输入框直接进行跳转。

VSCode 多文件搜索和替换

  • 多文件搜索的运行方法跟单文件搜索非常类似。单文件搜索,我们是通过按下“Cmd+ F” 来调出搜索窗口的,而多文件搜索则是通过按下 “Cmd + Shift + F” (Windows 上是 Ctrl + Shift + F)来调出多文件搜索的视图。

  • 默认情况下,当我们调出多文件搜索的视图时,VS Code 会在当前打开的文件夹下进行搜索。不过,要发挥多文件搜索的更大功效,我们可以通过书写配置来决定在哪些子文件夹下进行搜索,以及过滤掉哪些特殊的文件或者文件夹。

  • 要完成这样的配置,我们需要点击搜索框下三个点形状的图标,点开后,我们能看到两个输入框,它们的名字分别是“包含的文件” 和 “排除的文件”。这两个配置的书写格式是 glob,很多编程语言和配置都会使用 glob 来模糊匹配文件名和文件夹,估计你已经有所了解。而如果你不熟悉的话,就当作是课后作业了,这一定不是你最后一次需要书写 glob。

  • 第一个是 “search.collapseResults” 。它是用来控制是否自动展开搜索结果。默认的配置是 “auto” 自动, 也就是说,VS Code 会根据搜索结果的多少来决定是否要将某个文件下的搜索结果展开,如果某个文件夹下的结果过多的话,就会将其暂时折叠,用户需要展开结果。我自己喜欢将其设置为 “alwaysExpand”,这样我每次都能直接看到结果了。

  • 第二个是 “search.location” ,也就是多文件搜索视图的位置。默认情况下,搜索视图会出现在侧边栏。但是 VS Code 同样允许你把搜索视图放到底部面板中去,你只需将其修改为 “panel” 即可。相信很多用户都跟我一样,使用过非常多把搜索视图放在底部的开发工具,并且很习惯了,那这个设置就能够帮助到我们。

VSCode 行号

  • 我则是通过更改设置 editor.renderLineHighlight: “all” 把当前代码行的行号下的背景色也修改了,所以你可以看到图 2 的行号 5 的背景色也成为了绿色,整体上看起来更统一。

VSCode 渲染出空格符和制表符

  • 在图2中你能够在不少代码行前面看到灰色的“点”,这每一个“点”都代表着一个空格符。你可以通过设置 editor.renderWhitespace: all 让编辑器将所有的空格符、制表符等全部都渲染出来。这样你就能够一眼看出这个文件中使用的究竟是制表符还是空格符,以及有没有在哪里不小心多打了一个空格等。

VSCode 缩进参考线和垂直标尺

  • 编辑器会根据你指定的制表符的长度,来决定缩进参考线的位置。这样你就可以非常清楚地知道代码有没有正确地缩进,而且也方便你区分出不同代码块之间的层级关系。这个功能是可以通过 editor.renderIndentGuides 来控制开关的。

  • 而图2中的竖线则不一样了,它叫做垂直标尺。如果你的项目中有规定说每一行代码不得超过多少个字符,比如说120个字符,那么你就可以将标尺设置为 120,即 editor.rulers: [120]。这样的话编辑器就会在第120个字符所在的位置处画出这样一条垂直的竖线,所以你一眼就可以看出自己的代码是否达标。

VSCode 光标样式

  • 在图1中,光标是一条竖线,而在图2中光标则相对粗一些。编辑器中的光标样式有非常多种,你可以控制粗细,也可以控制它怎么闪烁。你需要调整的设置是 editor.cursorBlinking editor.cursorStyle 和 editor.cursorWidth。

VSCode 如何管理文件和文件夹

  • VS Code是如何管理文件和文件夹,首先需要说明的是,VS Code 的各个功能,都是基于当前打开的文件或者文件夹的。

  • 该怎么去理解这个概念呢?

    • 如果你使用过 IDE 的话, 你应该记得在第一次打开 IDE 的时候,它们往往需要你创建一个工程,这个工程会生成一个特殊的工程文件。这个工程文件记载了这个项目有哪些相关的文件、项目的配置、构建脚本等等。这个文件记录着 IDE 管理工程的元信息,开发团队也能够通过共享这个工程文件保证成员工作环境的一致性。但是工程文件对用户体验就不太友好了,比如说项目文件可能对 IDE 的版本有所要求,项目文件损坏了 IDE 读取不了但是我们也不知道如何修复,等等。
  • VS Code 则选择了一种相对轻量,而且大家都易于理解的方式,那就是所有的操作都基于文件和文件夹。当你打开一个文件夹,VS Code 的核心功能就会对这个文件夹进行分析,并提供对应的功能。比如,在打开的文件夹下检测到有 .git 文件,就加载 Git 插件来提供版本管理的功能;或者发现文件夹下有 tsconfig.json ,就会激活 TypeScript 插件提供语言服务

  • 当你第一次打开 VS Code 的时候,工作台中还没有打开任何文件夹。这时候在欢迎界面的左上方,你能够看到:“新建文件”和“打开文件夹”等这样的快捷键。

  • 未打开文件夹,状态栏为紫色

  • 这时候请注意工作台最下方的状态栏,当 VS Code 没有打开任何文件夹的时候,它的颜色是紫色的。而如果在工作台中打开了某个文件夹,状态栏的颜色就会变成蓝色。

VSCode 多文件夹工作区

  • VS Code 多文件夹工作区,多文件夹工作区(multi-root workspace)。老实说呢,这个概念是有一定的理解难度的。

  • 上面我们提到的基于文件夹的这种项目管理方式,从 VS Code 第一天开始就存在了。也几乎从第一天开始,我们就收到了用户对于这一个设计不满的反馈。对于这些不满的用户而言,他们的痛点在于他们经常需要同时对多个文件夹下的代码进行操作。但是 VS Code 关于单个文件夹的这种操作模式,要求了他们必须同时打开多个窗口,并不停地在它们之间切换。

  • 多文件夹工作区就是为了针对这个问题而实现的解决方案。那下面我们就一起来看一看怎样去创建一个多文件夹工作区。

  • 首先,在 VS Code 中打开一个文件夹,此时 VS Code 处于一个单文件夹的状态。然后你可以调出命令面板,搜索 “将文件夹添加到工作区” (add folder to workspace)并执行,或者使用菜单,“文件 —> 将文件夹添加到工作区”,这之后,选择你想要在当前窗口打开的文件夹。

  • 此时在资源管理器里的标题栏里,你能看到“无标题 (工作区)”这样的文字,这说明当前的工作区已经有多个文件夹了,只是现在你还没有保存这个多文件工作区,也没有给它指定一个名字。

  • 要保存这个工作区,接下来你可以调出命令面板,搜索“将工作区另存为” (save workspace as),VS Code 就会为这个工作区创建一个文件,这个文件的后缀名是 “code-workspace”。比如,在下面的动图中,我给这个工作区取名为 sample,然后指定在 Code中这个文件夹下保存。这样操作后,VS Code 就会在 Code 文件夹下创建一个 sample.code-workspace 文件。

  • 你可以看到,操作完之后资源管理器的标题栏已经相应地改变了。另外,sample.code-workspace 虽然有个特殊的后缀,但这个文件的格式其实也是 JSON,你可以自行打开这个文件查看一下。

  • 这个 JSON 文件,默认有两个键(key)。第一个是 folders 文件夹,它里面罗列的是这个多文件工作区里有哪些文件夹。可以看出,这些文件夹的地址,都是这个 sample.code-workspace 文件的相对路径。第二个则是 settings 设置,你可以在这个值里面添加专属于这个多文件夹工作区的设置。它的作用,跟上面我们介绍的 .vscode 文件夹下的 settings.json 文件是类似的。

VSCode 工作区切换

  • VSCode 工作区切换,如果你同时打开了多个窗口,可以按下 Ctrl + W,或者调出命令面板,搜索 “切换窗口(Switch Window)”,然后选择你要跳转的那个文件夹中去。
  • 如果你只是要跳转到上一个打开的窗口,那就更方便了。打开命令面板,搜索“快速切换窗口(Quick Switch Window)”并执行,就能够直接跳转到之前的窗口了,而无需再做选择。这里我倒是非常建议你给这个命令指定一个快捷键,这样你就能在窗口之间一键切换了。
  • 如果你同一时间只会关注一个项目,那你也大可不必使用多个窗口。我就经常只用一个显示器和一个窗口,然后当我想在另外一个项目上工作时,我就会按下 Ctrl + R(或者使用命令面板,搜索 “打开最近的文件”),此时我就能够看到最近操作过的文件夹并按下回车键进行切换了。
  • 当你按下 Ctrl + R 调出最近打开的文件夹的列表后,也能够按下 Cmd + 回车键,将它在一个新的窗口中打开。
  • 正是因为有上面这几个命令的存在,让我觉得没有多文件夹工作区也是可以的。当然,多文件夹工作区在某些方面的优势是不可比拟的,比如说跨文件夹的代码调试,这个我们后面也会介绍。

VSCode 代码调试器

  • VSCode 代码调试器,和语言功能一样,VS Code 是把调试功能的最终实现交给插件来完成的。VS Code 提供了一套通用的图形界面和交互方式,比如怎么创建断点、如何添加条件断点、如何查看当前调试状态下参数的值,等等。无论你使用哪个编程语言或者调试器,这一套交互流程都是相似的。

  • 而对于插件作者而言,他们需要完成的是如何把真正的调试工作跟 VS Code 的界面和交互结合起来,为此 VS Code 为插件作者提供了一套统一的接口,叫做Debug Adapter Protocol(DAP)。当用户在界面上完成一系列调试相关的操作时,VS Code 则通过 DAP 唤起调试插件,由插件完成最终的操作。

  • VS Code 中有一个专门的用于管理调试功能的视图。我们可以点击界面左侧“昆虫”(也就是 bug 啦)形状的按钮,或者按下 “Cmd + Shift + D” (Windows 上是 Ctrl + Shift + D)来唤出调试视图。

  • 在视图的最上侧,有个绿色的箭头按钮。这个按钮是用于启动调试器的。但是在上面的截图里,你可以看到在绿色箭头的右侧写着 “没有配置”。这说明现在 VS Code 还不知道该使用什么调试器来调试当前的代码。此时点击这个按钮或者按下 F5,我们能够看到一个列表。

  • 首先,我们将鼠标移动到第五行代码的行号前面,点击鼠标左键,我们能够看到一个红色的圆点被创建了出来,这就是断点。当然,我们也可以把光标移动到第五行,然后按下 F9,同样可以在第五行创建断点。

  • 此时,当我们再次点击调试视图上面的绿色箭头按钮,或者按下 F5,启动调试器,并且选择 Node.js ,VS Code 就会进入调试模式。

  • VSCode 代码调试器配置launch.json介绍,在调试视图的最上方,我们能够看到一个齿轮形状的按钮,它可以用于创建和修改 launch.json 文件。由于当前文件夹下没有 launch.json 文件,所以这个按钮的右上角有个红色的点,它告诉我们当前的调试配置有一点问题,让我们点击这个按钮。

  • 这个 JSON 文件里的 configurations 的值就是当前文件夹下所有的配置了。现在我们只有一个调试配置,它有四个属性:

    • 第一个是 type,代表着调试器的类型。它决定了 VS Code 会使用哪个调试插件来调试代码。
    • 第二个是 request,代表着该如何启动调试器。如果我们的代码已经运行起来了,则可以将它的值设为 attach,那么我们则是使用调试器来调试这个已有的代码进程;而如果它的值是 launch,则意味着我们会使用调试器直接启动代码并且调试
    • 第三个属性 name,就是这个配置的名字了。
    • 第四个属性 program,就是告诉 Node.js 调试器,我们想要调试哪个文件。这个值支持预定义参数,比如在上面的例子里,我们使用了${file},也就是当前编辑器里打开的文件。
  • 下面我们把 program 的值改为 ${workspaceFolder}/index.js,其中${workspaceFolder} 是代表当前工作区文件夹地址的预定义参数,使用它就能够准确地定位当前工作区里 index.js 文件了。(关于在配置文件里可以使用的预定义参数,请参考Visual Studio Code Variables Reference。 https://code.visualstudio.com/docs/editor/variables-reference

  • 通用属性

  • 虽然每个调试器各自控制着用户可以使用哪些属性,但是调试器之间还是有很多相同的地方,调试插件在很多时候都会使用相同的属性名来代表同样的功能。比如,我自己就是 Ruby 插件的作者,我在实现 Ruby 调试插件的时候,参考了很多 Node.js 和 PHP 调试插件对于属性的命名和使用。我在书写不同语言的调试配置时,经常使用的有下面这些:

    • program 一般用于指定将要调试的文件。
    • stopOnEntry,当调试器启动后,是否在第一行代码处暂停代码的执行。这个属性非常方便,如果没有设置断点而代码执行非常快的话,我们就会像文章的最开头那样,代码调试一闪而过,而没有办法在代码执行的过程中暂停了。而设置了 stopOnEntry 后,代码会自动在第一行停下来,然后我们就可以继续我们的代码调试了。
    • args 参数。相信你应该记得在前面任务系统配置的文章里,我已经说明了可以使用 args 来控制传入任务脚本的参数,同样的,我们也可以通过 args 来把参数传给将要被调试的代码。
    • env 环境变量。大部分调试器都使用它来控制调试进程的特殊环境变量。
    • cwd 控制调试程序的工作目录。
    • port 是调试时使用的端口。

VSCode 经典插件推荐

  • VSCode 经典插件推荐,今天我要介绍的是:能够在某些领域大幅度提高VS Code使用效率和体验的工具。能够取代 VS Code原有功能的工具。对插件 API 的使用别出心裁的工具。

Git

  • GitLens

  • VS Code中的 Git 体验在易用性和完整性之间取得了一个不错的平衡,大部分用户都能够使用它完成工作,同时又不会被太多的功能吓到。但是很多硬核的 Git 用户肯定会觉得功能还不够用。包括但不限于:

    • 不能查看某个 commit 中的代码改动;
    • 不能比较两个 commit 或者 branch,然后阅览代码改动;
    • 不能查看代码历史记录。
  • RemoteHub

  • GitLens 作者 Eric Amodio 又出一款力作——RemoteHub。安装这个插件后,当你想在本地看某个 GitHub repository的代码时,你就不需要将代码 clone 下来了,你可以直接打开这个 repository 相关的工作区,所有文件、文件夹都是从 GitHub 按需下载下来。如果你连接 GitHub 的网速不错的话,那么使用体验可是比 GitHub 网站要好得多。

  • GitHub Pull Request

  • 除了 Git 支持以外,一个呼声一直非常高的需求,就是在 VS Code中查看和审核 GitHub 上的 Pull Request。好消息是,VS Code团队和 GitHub 的 Editor Tools 团队一起合作,为我们提供了 GitHub Pull Request这个插件。

工作区

  • Settings Sync

  • 如何在不同设备之间同步个人设置?VS Code自己并没有提供设置的同步,但通过 Settings Sync这个插件,你可以将个人设置同步到 Gist 中。

  • 不过值得注意的是,虽然你的设置是同步到自己私人的 Gist 中,但是如果你的设置中有一些隐私信息,像密码、Token 之类的,还是不要使用此插件比较好。

  • Project Manager

  • 我们在工作台的部分,介绍过 VS Code支持多文件夹工作区(multi-root workspace),以及如何通过快捷键在不同的项目之间来回切换。如果你不喜欢 VS Code默认的方式,那么你也可以试试 Project Manager。Project Manager 甚至还有一个专门的视图来展示所有的项目,非常方便。

编辑器

  • VIM

  • 编辑器相关的插件中最厉害的应该就是 Vim 相关的插件了,VS Code提供了一个 API 保证了 Vim 插件能够被正确地实现。不过 Vim 插件并不只有一个,下载量最大的,也是我参与的就是 VSCodeVim,它对 Vim keybings 的覆盖程度非常高。另一个非常受大家欢迎的就是amVim,它的性能也非常不错。

  • Rainbow Brackets

  • 不管你是不是写函数式语言,当你的代码中有比较多的花括号时,要保证它们对称可以说是非常困难了。Rainbow Brackets这个插件,为同一对花括号指定一个单独的配色,这样你就能够轻松地一眼看出花括号的配对了。

  • Indent Rainbow

  • 上面的 Rainbow brackets 是给花括号加上多种颜色,而 Indent Rainbow则是为你的代码缩进提供颜色上的提示:

  • 这两个插件有异曲同工之妙,当然我还是建议写代码的时候,不要有太多的层级。

  • Pigment

  • 既然说到颜色,就不得不提Pigment 这个插件。在介绍择色器(Color Picker)的时候我介绍过,VS Code会在每个颜色前面加上一个方块,用方块来展示代码所对应的颜色。Pigment 则是将颜色渲染在这段代码的下面,我自己还是蛮喜欢这种方式的。

  • Import Cost

  • JavaScript 经常被吐槽的一个地方,就是大家对 npm 库的使用程度非常高,经常为了一个简单的功能,引入了几兆甚至十几兆的 npm 包。Import Cost这个插件,很好地在代码中给我们以提示,告诉我们引入的某个包,它最终会导致整个项目的大小增加多少。

调试:Debugger for Chrome

  • 虽然我们并不介绍语言相关的插件,但是还是有一个调试相关的插件值得一提,那就是 Debugger for Chrome。这个插件,允许在 VS Code中调试前段代码,这样你就不需要再使用 Chrome Dev Tools 了。你可以直接在自己的代码上加上断点,发现错误后直接修改,非常方便。

其他

  • Rest Client

  • 我们使用 REST API 的时候,经常需要发送一些样例数据对 API 进行测试,这时我们可以使用 Postman 这类的独立应用,也可以在 VS Code中使用 Rest Client插件,直接在编辑器里发送 REST 请求。

  • Code Runner

  • macOS 用户对 Code Runner 这个应用一定非常熟悉了,你可以使用 Code Runner 快速地书写代码并且执行,而无需设置环境配置工程之类的。VS Code里也有这样的插件,如果你有类似的需求,可以试一试。

  • Live Share

  • Live Share是微软官方出品的非常强大的服务,通过 Live Share service,你可以将你本地的工作区,直接分享给你的同伴,然后你的同伴就可以直接编辑你的代码,与你共享代码调试、集成终端等等,而无需安装任何环境。Atom 也有类似的服务叫做 Teletype。我工作中每次要和同事 Pair Programming 的时候,就会使用 Live Share。
    同时 Live Share 服务还支持语音通讯,不过需要安装另一个插件 Live Share Audio。

如何分享插件

  • 当然有!你可以通过在项目的 .vscode 文件夹下,创建一个文件 extensions.json。你很熟悉了,这又是一个 JSON 文件,在这个 JSON 文件里,你只需提供一个键(key) recommendations,然后将你想要推荐给这个项目的其他工程师的插件的 ID 们,全部放入到这个数组中。当他们打开这个项目,而且并没有安装这些插件时,VS Code就会给他们提示了。

  • 除了在 .vscode/extensions.json 文件推荐插件,如果你在使用多文件夹工作区(multi-root workspace),也可以在多文件夹工作区的配置文件里添加如下的设置:

VSCode C++ 配置

三个文件:task.json launch.json c_cpp_properties.json

  1. IntelliSense:Intelligence Sense,代码自动补全
  2. Task.json:
    告诉VScode如何编译.cpp文件,配置后将调用g++编译器基于源代码创建可执行文件。
    参数:
    command:设置要运行的指定程序
    args:参数数组指明要传送给g++的命令行参数,这些参数必须按照编译器要求的顺序来说明
    ${file}:g++执行的活动文件
    ${fileDirname}:当前目录
    label:任务列表中显示的值
  3. launch.json:使用F5启动GDB调试器来调试程序
  4. c_cpp_properties.json:对c/c++扩展实现更多控制,可以改变编译器的路径,C++标准以及更多

变量替换

  • VScode在launch.json调试文件和task.json任务文件中是支持变量替换的,这就意味着可以很方便的使用VScode一些预定以的变量。
  • 变量的使用方式:${variableName}
  • 常用的变量:
    • ${workspaceFolder} : 项目文件夹在VScode中打开的路径
    • ${file} : 当前打开的文件
    • ${relativeFile} : 相对于${workspaceFolder}的文件路径
    • ${fileBasename} : 当前打开文件的名称
    • ${fileBasenameNoExtension} : 当前打开文件的名称,不带扩展名
    • ${fileExtname} : 当前打开文件的扩展名
    • ${fileDirname} : 当前打开文件的文件夹名称

调试 断点

日志点,Logpoints

  • 日志点是断点的变体,它不会“中断”到调试器中,而是将消息记录到控制台。日志点对于再调试无法暂停或停止的生产服务器时注入日志记录特别有用。(A Logpoint is a variant of a breakpoint that does not “break” into the debugger but instead logs a message to the console. Logpoints are especially useful for injecting logging while debugging production servers that cannot be paused or stopped)
  • 日志消息是纯文本,但可以包含表达式,需要使用花括号

表达式条件断点

  • 条件断点是表达式结果为true时才会进行断点

命中计数断点

  • 只有该行代码命中了指定次数,才会进行断点

内联断点

  • 仅当执行到达与内联断点关联的列时,才会命中内联断点。
  • 这在调试一行中包含多个语句的缩小代码时特别有用。比如for循环,短路运算符等一行代码包含多个表达式时
  • 在指定位置按shift + F9

快捷键

  • ctrl + p : 快速搜索文件并跳转,添加:可以跳转到指定行
  • alt + 鼠标左键 : 选中多行同时编辑

简介

  • VSCode 编辑器常用的技巧

vscode windows下PATH环境变量更新,vscode未识别

  • 先退出VSCode
  • 打开cmd窗口,输入并执行 code 命令
  • 在新打开的VSCode的终端里,环境变量已经是最新的

vscode 页面切换到左侧工具栏

在 Visual Studio Code 中,如果你希望将焦点从编辑器切换到左侧的侧边栏(也称为 Activity Bar),可以使用以下方法:

  1. 使用键盘快捷键

    • 按下 Ctrl + 0(Windows/Linux)或者 Cmd + 0(Mac)可以将焦点从编辑器切换到侧边栏的第一个图标。
    • 使用 Ctrl + 1Ctrl + 2Ctrl + 3 等数字键(Windows/Linux)或者 Cmd + 1Cmd + 2Cmd + 3 等数字键(Mac)可以将焦点切换到侧边栏的不同图标。
  2. 使用鼠标

    • 直接点击侧边栏的图标来切换到相应的视图,例如资源管理器、搜索、源代码管理等。

这些方法可以帮助你快速地将焦点从编辑器切换到左侧的工具栏,以便访问不同的功能和视图。

vscode 分屏显示 切换

在 Visual Studio Code 中,你可以使用以下快捷键来实现分屏显示和切换:

  1. 分屏显示

    • 打开第一个文件后,按下 Ctrl + \(Windows/Linux)或者 Cmd + \(Mac)来进行分屏显示。这会在当前编辑器的右侧打开一个新的编辑器。
    • 或者,你可以通过右键点击文件选项卡,选择 “Split Editor”。
  2. 切换焦点

    • 使用 Ctrl + 1Ctrl + 2 等数字键(Windows/Linux)或者 Cmd + 1Cmd + 2 等数字键(Mac)来切换到不同的编辑器。
    • 或者,你可以使用 Ctrl + \(Windows/Linux)或者 Cmd + \(Mac)来切换焦点到分屏的另一个编辑器。
  3. 关闭分屏

    • 在分屏模式下,将鼠标悬停在编辑器的右上角,会看到一个关闭按钮(’X’)。点击该按钮可以关闭分屏。
  4. 重新分屏

    • 如果你只剩下一个编辑器,但是想要重新进行分屏,你可以使用 Ctrl + \(Windows/Linux)或者 Cmd + \(Mac)来重新分屏。

通过这些快捷键,你可以方便地在 Visual Studio Code 中进行分屏显示和切换。

日志断点调试

  • 断点模式设置为日志断点,输入表达式,随即会在output一栏输出
  • 例如输出变量command,则表达式为{command},随后回车就会输出

配置C++智能匹配

  • open the Command Palette (Ctrl+Shift+P)
  • enter Select IntelliSense Configuration.

配置C++

  • You can view the C/C++ configuration UI by running the command C/C++: Edit Configurations (UI) from the Command Palette (Ctrl+Shift+P).

简介

  • Asio库相关的理论基础知识

  • Asio库是仅包含头文件的库

C++ Asio库独立版本详解

Boost.Asio 是一个非常流行的 C++ 库,用于实现异步 I/O 操作和网络编程。它最初作为 Boost C++ 库的一部分,但后来成为 C++ 标准库的一部分(自 C++11 起)。因此,Boost.Asio 的某些版本也包含在 Boost 库中。

独立版本的 Boost.Asio 是指可单独使用、独立于 Boost 库的版本。它通常是从 Boost 库中分离出来的、具有更轻量级的库。这样的版本可以更容易地集成到项目中,而无需包含整个 Boost 库。

独立版本的 Boost.Asio 通常具有以下特点:

  1. 独立性: 它不需要完整的 Boost 库作为依赖,可以单独使用。
  2. 轻量级: 与完整的 Boost 库相比,其体积较小,减少了不必要的依赖。
  3. 简化构建和集成: 由于它是一个独立的库,因此在项目中使用起来更加方便,构建和集成更简单。

Boost.Asio 独立版本的详细内容和特性与原始的 Boost.Asio 库非常相似,主要提供异步 I/O、TCP、UDP、定时器和网络编程相关的功能。它仍然支持异步事件和异步操作,提供了用于管理 I/O 对象、定时器和网络通信的类和函数。

要使用独立版本的 Boost.Asio,你可以从官方的 GitHub 仓库或下载页获取源代码,并按照提供的指南进行构建和集成。通常,独立版本的 Boost.Asio 具有更加现代化和改进的特性,因为它们可能是从较新版本的 Boost 库中提取出来的。

请注意,独立版本的 Boost.Asio 可能会有所不同,具体取决于版本和发布的时间。因此,建议查看官方文档和版本说明以获取特定版本的详细信息和使用说明。

简介

  • Asio常用的类

Asio asio::io_context 详解

asio::io_context 是 Boost.Asio 库(也是 C++ 标准库中的一部分,自 C++17 起)中的核心类之一。它是实现异步 I/O 操作的关键部分,用于驱动异步事件处理。

作用:

  • 提供 I/O 上下文: io_context 对象是异步操作的执行上下文,用于管理异步操作、事件处理、任务队列和事件循环。
  • 事件驱动: 通过 io_context,可以注册异步操作(如套接字操作、定时器事件等),io_context 将在合适的时机进行调度、执行和完成这些异步操作。

主要功能和方法:

  • run() 开始 io_context 上的事件循环,处理已注册的所有异步操作,直到所有操作完成或 io_context 被停止。
  • stop() 停止 io_context 上的事件循环。停止后,run() 函数将在处理完当前已注册的操作后立即返回。
  • poll() 执行 io_context 上的事件循环,但仅处理当前可立即完成的操作,然后立即返回。
  • restart() 重新启动已经停止的 io_context

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <boost/asio.hpp>

int main() {
boost::asio::io_context io_context;

// 创建一个定时器
boost::asio::steady_timer timer(io_context, boost::asio::chrono::seconds(5));

// 异步等待定时器完成
timer.async_wait([](const boost::system::error_code& ec) {
if (!ec) {
std::cout << "Timer expired!" << std::endl;
}
});

// 运行 io_context 上的事件循环,直到所有操作完成
io_context.run();

return 0;
}

在上述示例中,io_context 用于驱动异步操作(这里是一个定时器异步等待)。通过调用 run() 方法,io_context 开始处理已注册的异步操作,并在完成所有操作或者遇到停止指令时返回。

io_context 是 Boost.Asio 中非常重要的一个类,它为异步操作提供了执行环境,能够有效地管理和调度异步事件,是异步编程的核心。

Asio asio::thread_pool 详解

asio::thread_pool 是 Boost.Asio 库中的一个类,它提供了一个线程池,用于管理和执行异步操作。线程池是一种用于管理线程的技术,它可以预先创建一组线程,以便在需要时执行任务或处理异步操作。

主要作用:

  • 管理线程: asio::thread_pool 提供了线程池,可用于执行异步操作,避免了频繁创建和销毁线程的开销。
  • 处理异步操作: 可以将异步操作(如定时器、套接字操作等)提交给线程池,线程池会自动将其分配到可用的线程上执行。

主要方法和功能:

  • asio::thread_pool(size_t num_threads) 构造函数: 创建具有指定数量线程的线程池。
  • ~thread_pool() 析构函数: 销毁线程池,等待所有线程执行完毕并释放资源。
  • submit(Function && function) 提交任务到线程池,执行 function 函数。
  • stop() 停止线程池,不再接受新的任务,等待所有任务执行完毕后销毁线程池。
  • join() 阻塞等待线程池中的所有任务执行完成。
  • notify_one()notify_all() 用于唤醒正在等待的线程。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/post.hpp>

void task() {
std::cout << "Task executed in thread: " << std::this_thread::get_id() << std::endl;
}

int main() {
boost::asio::thread_pool pool(4); // 创建有4个线程的线程池

// 提交任务到线程池
for (int i = 0; i < 8; ++i) {
boost::asio::post(pool, task);
}

// 等待所有任务完成
pool.join();

return 0;
}

在上述示例中,创建了一个具有 4 个线程的线程池 pool,然后向线程池提交了 8 个任务。这些任务会被线程池中的线程异步执行。最后,调用 pool.join() 阻塞等待所有任务执行完成。

asio::thread_pool 提供了一种有效地管理和执行异步操作的方式,避免了线程频繁创建和销毁的开销,并提高了异步操作的执行效率。

Asio asio::ip::tcp::socket 详解

asio::ip::tcp::socket 是 Boost.Asio 库中用于 TCP 协议的套接字类,用于在 C++ 中进行 TCP 网络通信。

主要作用:

  • 实现 TCP 客户端和服务器: asio::ip::tcp::socket 允许 C++ 应用程序创建 TCP 客户端或服务器套接字,并进行数据传输。

主要方法和功能:

  • constructor 构造函数: 创建 TCP 套接字。
  • open() 打开套接字。
  • close() 关闭套接字。
  • connect() 用于客户端,连接到远程服务器。
  • async_connect() 异步连接到远程服务器。
  • bind() 将套接字与本地端口或地址绑定。
  • async_bind() 异步绑定套接字。
  • listen() 在服务器上监听传入连接请求。
  • accept() 接受传入的连接请求。
  • async_accept() 异步接受传入的连接请求。
  • read_some()write_some() 同步读取和写入数据。
  • async_read_some()async_write_some() 异步读取和写入数据。
  • shutdown() 关闭套接字的输入、输出或全部流。

示例(简化的服务器端):

下面是一个简化的 Boost.Asio TCP 服务器端示例,展示了如何使用 asio::ip::tcp::socket 接受连接和读取数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

int main() {
boost::asio::io_context io_context;
tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 8080));

while (true) {
tcp::socket socket(io_context);
acceptor.accept(socket);

std::array<char, 128> buffer;
boost::system::error_code error;

// 读取数据
size_t len = socket.read_some(boost::asio::buffer(buffer), error);
if (error == boost::asio::error::eof) {
std::cout << "Connection closed by peer." << std::endl;
} else if (error) {
std::cerr << "Error: " << error.message() << std::endl;
} else {
std::cout << "Received data: " << std::string(buffer.data(), len) << std::endl;
}
}

return 0;
}

asio::ip::tcp::socket 是 Boost.Asio 中用于 TCP 通信的关键类之一,提供了处理 TCP 套接字的方法和功能,可以用于创建 TCP 客户端或服务器,并进行数据的读写操作。

Asio asio::steady_timer详解

asio::steady_timer 是 Boost.Asio 库中的一个定时器类,用于在指定时间点执行或触发操作。

主要作用:

  • 定时触发事件: asio::steady_timer 用于创建定时器对象,可以在设定的时间点之后触发回调函数。

主要方法和功能:

  • constructor 构造函数: 创建定时器对象。
  • expires_at()expires_from_now() 分别设置定时器的到期时间和到期时刻的相对偏移量。
  • async_wait() 异步等待定时器触发。可以向定时器对象提交一个回调函数,在指定时间点触发回调。
  • cancel() 取消定时器,终止尚未触发的操作。
  • wait() 阻塞等待定时器触发。

示例:

下面是一个简单的 Boost.Asio 定时器示例,演示了 asio::steady_timer 的基本用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <boost/asio.hpp>

void timer_handler(const boost::system::error_code& ec) {
if (!ec) {
std::cout << "Timer expired!" << std::endl;
}
}

int main() {
boost::asio::io_context io_context;
boost::asio::steady_timer timer(io_context, boost::asio::chrono::seconds(5));

// 异步等待定时器触发,并指定回调函数
timer.async_wait(timer_handler);

// 运行 io_context 上的事件循环
io_context.run();

return 0;
}

在上述示例中,创建了一个 asio::steady_timer 对象 timer,设置定时器在 5 秒后触发。然后使用 timer.async_wait() 异步等待定时器的触发,并指定了一个回调函数 timer_handler。最后,调用 io_context.run() 运行事件循环,等待定时器触发并执行回调函数。

asio::steady_timer 类是 Boost.Asio 中用于管理定时器的重要类之一,允许程序在指定的时间点执行特定操作,通常用于实现定时任务、超时控制等功能。

简介

  • Asio相关的函数

Asio asio::chrono::seconds()函数 详解

在 Boost.Asio 中,asio::chrono::seconds() 函数是用于创建时间持续时间(duration)对象的函数,表示以秒为单位的时间段。

这个函数位于 Boost.Asio 的时间相关命名空间中,asio::chrono,用于创建与时间相关的持续时间对象,其中包括 std::chrono::duration 的各种变种。

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <boost/asio.hpp>

int main() {
// 使用 asio::chrono::seconds() 创建秒数为 5 的持续时间对象
boost::asio::steady_timer timer(boost::asio::chrono::seconds(5));

// 打印定时器的过期时间(当前时间加上 5 秒)
std::cout << "Timer will expire after 5 seconds." << std::endl;

return 0;
}

在上述示例中,asio::chrono::seconds(5) 创建了一个表示 5 秒的时间段,然后将该时间段传递给 boost::asio::steady_timer 的构造函数,用于设置定时器在 5 秒后触发。

此函数的作用在于以秒为单位创建时间段,可以用于设置定时器、指定等待时间等场景。 Boost.Asio 中的这些时间函数通常是与异步操作和定时器相关的,使得在异步编程中方便地创建和管理时间段。

Asio asio::steady_timer::async_wait() 函数 详解

asio::steady_timer::async_wait() 是 Boost.Asio 中 steady_timer 类的成员函数,用于异步等待定时器到期并触发回调函数。

函数签名:

1
2
template <typename WaitHandler>
void async_wait(WaitHandler&& handler);

参数说明:

  • WaitHandler:一个可调用对象,用于处理定时器到期时触发的回调函数。可以是函数指针、函数对象、lambda 函数等。

功能:

async_wait() 函数安排一个异步操作,在指定的定时器到期时执行回调操作。该函数不会阻塞当前线程,而是在设置的时间段之后触发回调函数。

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <boost/asio.hpp>

void timer_handler(const boost::system::error_code& ec) {
if (!ec) {
std::cout << "Timer expired!" << std::endl;
}
}

int main() {
boost::asio::io_context io_context;
boost::asio::steady_timer timer(io_context, boost::asio::chrono::seconds(5));

// 异步等待定时器触发,并指定回调函数
timer.async_wait(timer_handler);

// 运行 io_context 上的事件循环
io_context.run();

return 0;
}

在上述示例中,async_wait() 函数用于异步等待定时器 timer 到期,并指定了一个名为 timer_handler 的回调函数处理定时器到期时的操作。io_context.run() 开始运行事件循环,等待定时器触发并执行回调函数。

该函数常用于异步编程中,用于设置定时器的到期事件,并在到期时执行相应的操作或回调函数。

Asio asio::steady_timer::expires_at() 函数 详解

asio::steady_timer::expires_at() 是 Boost.Asio 中 steady_timer 类的成员函数之一,用于设置定时器的到期时间点。

函数签名:

1
2
template <typename TimePoint>
void expires_at(const TimePoint& time_point);

参数说明:

  • TimePoint:表示时间点的类型,通常为 std::chrono::time_point,用于指定定时器的到期时间点。

功能:

expires_at() 函数用于设置定时器 steady_timer 的到期时间点。当调用该函数并传递一个特定的时间点参数时,定时器将在指定的时间点触发,即执行定时器的回调函数或触发定时器到期事件。

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <boost/asio.hpp>

int main() {
boost::asio::io_context io_context;
boost::asio::steady_timer timer(io_context);

// 设置定时器到期时间点为当前时间加上 5 秒
timer.expires_at(std::chrono::steady_clock::now() + std::chrono::seconds(5));

// 异步等待定时器触发
timer.async_wait([](const boost::system::error_code& ec) {
if (!ec) {
std::cout << "Timer expired!" << std::endl;
}
});

// 运行 io_context 上的事件循环
io_context.run();

return 0;
}

在上述示例中,timer.expires_at() 用于设置定时器 timer 的到期时间点为当前时间加上 5 秒。随后使用 timer.async_wait() 异步等待定时器触发,在定时器到期时执行回调函数。最后,通过 io_context.run() 开始运行事件循环,等待定时器到期并执行回调函数。

expires_at() 函数对于预先设置定时器的到期时间非常有用,允许在稍后的时间点触发异步操作,使得在异步编程中更容易地控制定时器的触发时间。

Asio asio::steady_timer::expiry() 详解

在 Boost.Asio 中,asio::steady_timer::expiry()steady_timer 类的成员函数,用于获取定时器的到期时间点。

方法签名:

1
std::chrono::steady_clock::time_point expiry() const noexcept;

功能:

expiry() 方法用于获取当前设置的定时器 steady_timer 的到期时间点。返回的是一个 std::chrono::steady_clock::time_point 对象,表示定时器将会到期的时间点。

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <boost/asio.hpp>

int main() {
boost::asio::io_context io_context;
boost::asio::steady_timer timer(io_context);

// 设置定时器到期时间点为当前时间加上 5 秒
timer.expires_at(std::chrono::steady_clock::now() + std::chrono::seconds(5));

// 获取定时器的到期时间点并打印
std::chrono::steady_clock::time_point expiry_time = timer.expiry();
std::time_t expiry_time_c = std::chrono::steady_clock::to_time_t(expiry_time);
std::cout << "Timer will expire at: " << std::ctime(&expiry_time_c);

io_context.run();

return 0;
}

在这个示例中,使用 timer.expires_at() 将定时器 timer 的到期时间点设置为当前时间加上 5 秒。然后调用 expiry() 方法获取定时器的到期时间点,并将其转换为 std::time_t 格式,最后使用 std::ctime() 打印定时器将会到期的时间点。

expiry() 方法对于需要了解定时器何时到期的情况非常有用,它允许程序员检查定时器当前的到期时间点,以便在需要时执行相应的操作。

Asio asio::make_strand() 详解

在 Boost.Asio 中,asio::make_strand() 是一个用于创建 strand 对象的工厂函数。strand 提供了一种同步操作访问序列化(serialized)的方式,用于确保异步操作在多个线程中按照顺序执行,避免出现竞争条件。

函数签名:

1
2
template <typename ExecutionContext>
typename associated_executor<ExecutionContext>::type make_strand(ExecutionContext& context);

参数说明:

  • ExecutionContext:表示执行上下文的类型,可以是 io_contextstrand 或其他支持的执行上下文类型。

返回值:

  • 返回创建的 strand 对象。

功能:

make_strand() 函数用于创建一个 strand,它实际上是一个执行器(executor),可以确保在同一个 strand 内排队的操作按顺序执行,而不会发生竞争条件。

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <boost/asio.hpp>

int main() {
boost::asio::io_context io_context;

// 创建一个 strand 对象
auto strand = boost::asio::make_strand(io_context);

// 在 strand 内执行异步操作
boost::asio::post(strand, []() {
std::cout << "Task 1 executed in strand!" << std::endl;
});

boost::asio::post(strand, []() {
std::cout << "Task 2 executed in strand!" << std::endl;
});

io_context.run();

return 0;
}

在这个示例中,make_strand() 创建了一个 strand 对象 strand,然后使用 boost::asio::post() 将两个任务(lambda 函数)提交到 strand 内执行。由于这两个任务被提交到同一个 strand 中,它们会按照顺序在该 strand 中执行,避免了并发操作可能引发的竞争条件。

strand 对于需要序列化异步操作的情况非常有用,可以确保在一个特定的执行上下文中操作按顺序执行,增加了程序的可靠性和安全性。

Asio asio::bind_executor() 详解

在 Boost.Asio 中,asio::bind_executor() 是一个用于绑定执行上下文(executor)到处理器(handler)上的函数,它用于创建一个新的处理器对象,将给定的执行上下文绑定到现有的处理器上,从而确保处理器在指定的执行上下文中执行。

函数签名:

1
2
template <typename Executor, typename Handler>
decltype(auto) bind_executor(const Executor& ex, Handler&& handler);

参数说明:

  • Executor:表示执行上下文的类型,例如 io_contextstrand
  • Handler:表示处理器的类型,可以是函数对象、函数指针或者可调用对象。

返回值:

  • 返回一个新的处理器对象,将给定的执行上下文与原有的处理器绑定在一起。

功能:

bind_executor() 函数用于创建一个新的处理器对象,它在调用原始处理器时,会确保使用提供的执行上下文(executor)进行执行。这样做可以确保处理器在指定的执行上下文中运行,从而实现异步操作的序列化和控制。

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <boost/asio.hpp>

int main() {
boost::asio::io_context io_context;

// 创建一个 strand 对象
boost::asio::strand<boost::asio::io_context::executor_type> strand(io_context.get_executor());

// 绑定执行上下文到处理器
auto handler = asio::bind_executor(strand, [](const boost::system::error_code& ec) {
if (!ec) {
std::cout << "Handler executed in strand!" << std::endl;
}
});

// 执行处理器(实际上是在 strand 内执行)
handler(boost::system::error_code()); // 模拟传递错误码

io_context.run();

return 0;
}

在这个示例中,asio::bind_executor() 函数将一个处理器对象(lambda 函数)与一个执行上下文(strand)绑定在一起。然后,通过调用返回的新处理器对象 handler,可以确保该处理器在指定的 strand 中运行,从而保证了处理器的操作在该执行上下文中进行。这种绑定执行上下文到处理器的方式常用于确保异步操作的顺序执行或者将处理器绑定到特定的执行上下文中执行。

简介

  • boost库相关的笔记

Boost 库 编译 教程 详解

Boost C++ 库是一个非常强大的 C++ 库,提供了大量的功能和工具,包括智能指针、多线程、正则表达式、容器、图形学等。编译 Boost 库可能会有一些复杂性,因为 Boost 包含了大量的头文件和库,但下面是一个简要的教程,演示如何编译 Boost 库。

步骤 1:下载 Boost 库

首先,您需要下载 Boost 库的源代码。您可以从 Boost 官方网站(https://www.boost.org/)下载最新版本的 Boost 库。将源代码文件解压到您选择的目录中。

步骤 2:打开终端

在终端中导航到 Boost 库的源代码目录。您可以使用 cd 命令切换到该目录。

步骤 3:运行 Bootstrap 脚本

Boost 提供了一个名为 bootstrap.sh(Linux/macOS)或 bootstrap.bat(Windows)的脚本,用于配置编译过程。在终端中运行以下命令:

对于 Linux/macOS:

1
./bootstrap.sh

对于 Windows:

1
bootstrap.bat

这将为您的系统配置 Boost 库的编译过程。

步骤 4:运行 b2 命令

接下来,您需要运行 b2 命令来编译 Boost 库。您可以使用以下命令:

1
./b2

这将默认编译所有 Boost 库的组件。如果您只需要特定的库,您可以在 b2 命令后面添加库名称,例如:

1
./b2 --prefix=/tmp/boost --with-filesystem --with-system

这将仅编译文件系统和系统库。

步骤 5:等待编译完成

编译 Boost 库可能需要一些时间,具体取决于您的系统性能和所选的库。一旦编译完成,您将在 Boost 源代码目录中找到生成的库文件。

步骤 6:安装 Boost 库

您可以选择将编译后的库文件安装到系统目录中,以便其他项目可以轻松使用它们。运行以下命令:

1
sudo ./b2 install

这将把库文件复制到系统的默认位置。

注意:在 Windows 上,您可能需要使用 Visual Studio 编译工具来编译 Boost 库。您可以在 Boost 官方网站上找到有关使用 Visual Studio 的更多信息。

这是一个简要的 Boost 库编译教程。具体的步骤可能因您的系统和需求而有所不同。为了获得更详细的信息和特定于您的平台的说明,请查阅 Boost 文档或参考 Boost 官方网站上的编译指南。

cmake中引用Boost库

  • 通过调用find_package可以找到头文件和所需要的库文件或者是一个CMake打包配置文件

    1
    2
    3
    4
    5
    find_package(Boost
    [version] [EXACT] # 可选项,最小版本或者确切所需版本
    [REQUIRED] # 可选项,如果找不到所需库,报错
    [COMPONENTS <libs>...] # 所需的库名称,比如说. "date_time" 代表 "libboost_date_time"
    )
  • 示例

    1
    2
    find_package(Boost 1.62.0 REQUIRED
    COMPONENTS system filesystem thread)
  • 运行之后可以得到很多变量,下面列了一些主要的:

    1
    2
    3
    4
    5
    6
    Boost_FOUND            - 如果找到了所需的库就设为true
    Boost_INCLUDE_DIRS - Boost头文件搜索路径
    Boost_LIBRARY_DIRS - Boost库的链接路径
    Boost_LIBRARIES - Boost库名,用于链接到目标程序
    Boost_VERSION - 从boost/version.hpp文件获取的版本号
    Boost_LIB_VERSION - 某个库的版本
  • 如果Boost库是自定义安装路径,可以在搜索package之前,通过设置一些变量来帮助boost库查找

    1
    2
    3
    4
    BOOST_ROOT             - 首选的Boost安装路径
    BOOST_INCLUDEDIR - 首选的头文件搜索路径 e.g. <prefix>/include
    BOOST_LIBRARYDIR - 首选的库文件搜索路径 e.g. <prefix>/lib
    Boost_NO_SYSTEM_PATHS - 默认是OFF. 如果开启了,则不会搜索用户指定路径之外的路径
  • 如果目标程序foo需要链接Boost库的regex和system,编写如下的CMakeist文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # CMakeLists.txt
    project(tutorial-0)
    cmake_minimum_required(VERSION 3.7)
    set(CMAKE_CXX_STANDARD 14)

    set(BOOST_ROOT /usr/local/install/boost_1_62_0) // 设置boost库搜索路径
    set(Boost_NO_SYSTEM_PATHS ON) // 只搜索上语句设置的搜索路径

    find_package(Boost COMPONENTS regex system REQUIRED)

    if(Boost_FOUND)
    include_directories(${Boost_INCLUDE_DIRS})

    MESSAGE( STATUS "Boost_INCLUDE_DIRS = ${Boost_INCLUDE_DIRS}.")
    MESSAGE( STATUS "Boost_LIBRARIES = ${Boost_LIBRARIES}.")
    MESSAGE( STATUS "Boost_LIB_VERSION = ${Boost_LIB_VERSION}.")

    add_executable(foo foo.cpp)
    target_link_libraries (foo ${Boost_LIBRARIES})
    endif()
  • 通过设置BOOST_ROOT来设置首选的搜索路径

  • 通过MESSAGE函数把差找的结果都打印出来

  • Boost动态库链接。如果项目包含多个子模块,且子模块只用到顶层模块find_package找到的部分库,则用下述语句实现只链接子模块需要的Boost动态库

    1
    target_link_libraries(foo Boost::regex) // 只使用regex
  • Boost头文件库链接。在Boost库中有部分库只用头文件实现,并没有响应的动态库,若使用这部分库可以通过以下语句实现

    1
    2
    3
    target_link_libraries(foo Boost::boost)
    or
    target_include_directories(${Boost_INCLUDE_DIRS})

Boost C++ 库 使用示例 详解

Boost C++ 库包含了众多功能和组件,因此无法在一篇回答中详尽介绍所有。下面将展示一个使用 Boost 库的示例,涵盖智能指针、正则表达式和文件系统三个常用部分。请确保您已经成功编译了 Boost 库并将其包含在项目中。

1. 智能指针(Smart Pointers)示例:

智能指针帮助管理动态分配的内存,防止内存泄漏。以下是一个使用 Boost 智能指针的示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <boost/shared_ptr.hpp>
#include <iostream>

int main() {
boost::shared_ptr<int> sharedInt(new int(42));

std::cout << "Shared pointer value: " << *sharedInt << std::endl;
std::cout << "Reference count: " << sharedInt.use_count() << std::endl;

// sharedInt 在离开作用域时会自动释放内存
return 0;
}

在上述示例中,我们使用了 boost::shared_ptr 来创建一个智能指针,它会自动管理整数的内存分配和释放。use_count() 函数用于获取引用计数。

2. 正则表达式示例:

Boost.Regex 提供了强大的正则表达式功能。以下是一个使用 Boost.Regex 的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <boost/regex.hpp>
#include <iostream>
#include <string>

int main() {
std::string text = "Boost Libraries are awesome!";
boost::regex reg("Boost.*awesome");

if (boost::regex_search(text, reg)) {
std::cout << "Match found!" << std::endl;
} else {
std::cout << "No match found." << std::endl;
}

return 0;
}

上述示例中,我们使用 boost::regex 创建了一个正则表达式,然后使用 boost::regex_search 检查字符串中是否包含匹配的文本。

3. 文件系统示例:

Boost 文件系统库提供了文件和目录操作功能。以下是一个使用 Boost 文件系统库的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <boost/filesystem.hpp>
#include <iostream>

int main() {
boost::filesystem::path dirPath("./my_directory");

if (boost::filesystem::exists(dirPath)) {
if (boost::filesystem::is_directory(dirPath)) {
std::cout << "Directory exists." << std::endl;
} else {
std::cout << "Not a directory." << std::endl;
}
} else {
std::cout << "Directory does not exist." << std::endl;
}

return 0;
}

在上述示例中,我们使用 boost::filesystem::path 表示目录路径,并使用 boost::filesystem::existsboost::filesystem::is_directory 函数来检查目录是否存在以及是否为目录。

这些示例涵盖了 Boost C++ 库的一小部分功能。要使用 Boost 的其他组件和功能,请查阅 Boost 官方文档,其中包含了详细的教程和示例代码,以帮助您更好地理解和应用 Boost 库的各个组件。

Boost C++ 库 详解

Boost C++ 库是一个非常受欢迎的开源 C++ 库集合,提供了各种功能和工具,用于增强 C++ 编程,包括数据结构、算法、多线程、正则表达式、智能指针、文件系统操作等。以下是 Boost C++ 库的一些主要组成部分和功能的详细介绍:

  1. 智能指针(Smart Pointers):Boost 提供了各种智能指针,如 shared_ptrunique_ptrweak_ptr,用于管理动态分配的内存,以避免内存泄漏和提高代码安全性。

  2. 容器和数据结构:Boost 包括许多增强的容器和数据结构,如 unordered_mapunordered_setmulti_indexvariantany,用于更有效地管理数据。

  3. 多线程支持:Boost 提供了一套多线程库,包括线程、锁、条件变量和原子操作,以便于编写并发程序。

  4. 正则表达式:Boost.Regex 提供了强大的正则表达式库,使您可以进行高级文本匹配和处理。

  5. 文件系统:Boost 文件系统库允许您进行文件和目录的操作,包括文件检查、复制、移动和删除。

  6. 日期时间和时间戳:Boost.Date_Time 库提供了日期、时间和时间戳处理的功能,可用于处理时间相关的任务。

  7. 图形学库:Boost.Graph 库用于图形算法和数据结构,支持图形遍历、搜索和分析。

  8. 泛型编程和元编程:Boost 具有强大的泛型编程和元编程工具,包括预处理器宏、类型萃取和模板元编程,用于创建通用、高效的代码。

  9. 库之间的交互性:Boost 库之间通常能够很好地协同工作,因此您可以轻松地将它们组合在一起,以满足特定需求。

  10. 跨平台性:Boost 在多种操作系统和编译器上都能正常工作,因此它具有很强的跨平台性。

  11. 社区支持:Boost 是一个由社区驱动的项目,拥有广泛的用户和开发者社区,因此您可以在社区中获得支持和解答问题。

  12. C++标准化贡献:Boost 库中的一些功能已被采纳并成为 C++ 标准库的一部分,如智能指针 (std::shared_ptrstd::unique_ptr) 和正则表达式 (std::regex)。

要使用 Boost 库,通常需要将其源代码包括头文件和库链接到您的项目中。您可以在 Boost 官方网站上找到详细的文档和教程,以帮助您入门和使用 Boost 库的各个组件。Boost 提供了广泛的文档和示例代码,以便您更好地理解和使用这些功能。

简介

  • Boost 库概述

cmake配置boost

1
2
3
4
5
6
7
8
9
10
11
find_package(Boost 1.86 REQUIRED COMPONENTS system filesystem PATHS "${BaseDIR}/packages/boost_1_86_0/lib/cmake/Boost-1.86.0/" )
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})

MESSAGE( STATUS "Boost_INCLUDE_DIRS = ${Boost_INCLUDE_DIRS}.")
MESSAGE( STATUS "Boost_LIBRARIES = ${Boost_LIBRARIES}.")
MESSAGE( STATUS "Boost_LIB_VERSION = ${Boost_LIB_VERSION}.")

add_executable(foo foo.cpp)
target_link_libraries (foo ${Boost_LIBRARIES})
endif()

C++ boost库是什么

Boost 是一个功能强大的 C++ 库集合,为开发者提供广泛的、可移植的功能扩展。它被设计为标准库(STL)的补充,是现代 C++ 编程的重要工具。Boost 提供了许多高质量的库,涵盖了文件系统操作、多线程处理、智能指针、正则表达式、图算法等多个领域。


Boost 的主要特点

  1. 跨平台支持:Boost 的库可以在不同操作系统和编译器之间无缝工作。
  2. 标准化来源:Boost 的许多功能后来被采纳进了 C++ 标准库,例如 std::shared_ptr 和正则表达式。
  3. 模块化设计:Boost 包含了 100 多个模块,开发者可以按需使用特定的库,而不需要加载整个库集合。
  4. 高性能和可靠性:Boost 提供的功能经过社区的广泛测试和优化,性能优异且稳定。

Boost 的常用模块

以下是一些常用的 Boost 模块及其功能:

  1. Boost.SmartPtr
    提供智能指针(如 shared_ptr, weak_ptr),简化内存管理。

    1
    2
    #include <boost/shared_ptr.hpp>
    boost::shared_ptr<int> p(new int(10));
  2. Boost.Regex
    提供强大的正则表达式功能,类似于 std::regex

    1
    2
    #include <boost/regex.hpp>
    boost::regex expr("(\\w+)@(\\w+\\.\\w+)");
  3. Boost.Thread
    实现多线程编程,包括线程同步工具(如 mutexcondition_variable)。

    1
    2
    3
    #include <boost/thread.hpp>
    boost::thread t([] { std::cout << "Hello from Boost.Thread!" << std::endl; });
    t.join();
  4. Boost.Filesystem
    提供跨平台的文件和目录操作。

    1
    2
    #include <boost/filesystem.hpp>
    boost::filesystem::path p("/path/to/file");
  5. Boost.Asio
    支持异步输入输出(I/O)操作,用于网络编程和异步任务管理。

    1
    2
    3
    #include <boost/asio.hpp>
    boost::asio::io_context io;
    boost::asio::steady_timer timer(io, boost::asio::chrono::seconds(5));
  6. Boost.Serialization
    支持对象序列化和反序列化。

    1
    2
    3
    #include <boost/archive/text_oarchive.hpp>
    boost::archive::text_oarchive oa(std::cout);
    oa << my_object;
  7. Boost.Graph
    提供图算法和数据结构,用于复杂的图计算。


Boost 的安装与使用

  1. 下载与安装

    • Boost 官方网站 下载最新版本。
    • 解压后构建必要的库(静态或动态):
      1
      2
      ./bootstrap.sh
      ./b2
  2. 项目中使用 Boost

    • 在编译器中添加 Boost 的头文件路径:
      1
      g++ main.cpp -I /path/to/boost/include -L /path/to/boost/lib -lboost_system

Boost 的使用场景

  • 高效的内存管理:通过智能指针管理动态分配的内存,避免内存泄漏。
  • 跨平台文件操作:使用 Boost.Filesystem 处理文件路径和文件操作。
  • 异步编程:Boost.Asio 提供高效的异步任务处理和网络编程支持。
  • 多线程开发:Boost.Thread 为跨平台线程编程提供一致的接口。

Boost 的优缺点

优点:

  • 提供大量实用工具,节省开发时间。
  • 社区活跃,文档详尽。
  • 与 C++ 标准库深度结合,部分功能已纳入 C++ 标准。

缺点:

  • 有些模块的学习曲线较陡。
  • 部分库构建耗时较长。
  • 在某些情况下,库的体积较大。

相关资源

BOOST库 有哪些模块 详解

Boost 库是一个流行的 C++ 库集合,提供了各种各样的模块和功能,涵盖了多个领域,包括但不限于数据结构、算法、多线程、文件系统、网络编程、数学计算等。下面是一些主要的 Boost 模块:

  1. Boost.Asio:提供异步 I/O 和网络编程功能,包括套接字、TCP、UDP、定时器、异步任务等,用于构建高性能网络应用程序。

  2. Boost.Beast:基于 Boost.Asio,提供对 HTTP、WebSocket 和网络通信的支持,简化了处理 HTTP 和 WebSocket 协议的操作。

  3. Boost.Filesystem:提供了对文件系统操作的抽象接口,包括文件路径操作、文件/目录的创建、删除、移动、复制等。

  4. Boost.ThreadBoost.Atomic:提供了多线程和原子操作的支持,使得在 C++ 中更容易编写并发代码。

  5. Boost.Container:提供了一系列 STL 容器的扩展和优化版本,如 flat_map、flat_set、static_vector 等,增强了标准库中的容器功能。

  6. Boost.Graph:提供了图论相关的数据结构和算法,包括图的表示、遍历、最短路径等操作。

  7. Boost.Math:提供了数学计算的库,包括数值计算、特殊函数、概率分布、统计函数等,用于处理数学问题。

  8. Boost.Serialization:提供了用于对象序列化和反序列化的库,可以将对象转换为字节流以便存储或传输,并从字节流恢复为对象。

  9. Boost.Regex:提供了正则表达式的功能,用于文本匹配和处理。

  10. Boost.Date_Time:提供了日期和时间处理的库,包括日期时间表示、格式化、时区处理等。

  11. Boost.PropertyTree:用于处理树状结构的数据,例如 XML、JSON 等格式的数据。

  12. Boost.UUID:用于生成和操作 UUID(通用唯一标识符)的库。

  13. Boost.Test:提供了单元测试框架,用于进行 C++ 程序的单元测试。

  14. Boost.Locale:提供了本地化和国际化支持,包括字符集转换、日期时间格式化、货币格式化等功能。

  15. Boost.Process:提供了对进程的管理和操作功能。

以上列举的模块只是 Boost 库中的一小部分,Boost 还包含许多其他模块和库,每个模块都专注于不同的领域,为 C++ 开发提供了广泛的工具和功能支持。每个模块都有其自己的文档和用法,开发者可以根据需要选择并使用适合的模块。

简介

  • C编程语言相关的笔记

文件

  • C_1_理论基础.md [archive]
    • C_1_理论基础.pdf
  • C_2_重要函数.md
  • C_3_编程技巧.md
  • C_4_1_常用函数.md [archive]
    • C_4_1_常用函数.pdf
  • C_4_2_常用函数.md

简介

  • BOOST常用编程技巧

boost::filesystem::path 转 std::string

要将 boost::filesystem::path 转换为 std::string,你可以使用 boost::filesystem::path 对象的 string() 成员函数。这个函数返回一个表示路径的 std::string。以下是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <boost/filesystem.hpp>
#include <iostream>
#include <string>

int main() {
boost::filesystem::path filePath("/path/to/your/file.txt");

// 将 boost::filesystem::path 转换为 std::string
std::string filePathString = filePath.string();

// 打印转换后的 std::string
std::cout << "File path as string: " << filePathString << std::endl;

return 0;
}

在这个示例中,filePath.string() 函数将 boost::filesystem::path 对象 filePath 转换为一个 std::string,然后我们将其打印出来。

简介

  • boost常用函数

boost::ignore_unused()

boost::ignore_unused() 不是一个函数,而是一个辅助函数宏,用于防止编译器产生“未使用变量”的警告。这个宏是在 Boost 库中定义的,位于 <boost/core/ignore_unused.hpp> 头文件中。

在 C++中,如果你声明了一个变量但在后续的代码中没有使用,编译器可能会发出警告。为了避免这样的警告,可以使用 boost::ignore_unused() 来告诉编译器你有意不使用这个变量。

下面是 boost::ignore_unused() 的简要说明和示例:

  1. 函数签名:

    1
    2
    template <class... Ts>
    inline void ignore_unused(Ts const&...) noexcept;

    这个宏接受任意数量的参数,并在编译时告诉编译器忽略这些参数的未使用警告。

  2. 使用场景:

    • 防止未使用变量的警告: 当你有意声明了一个变量但在后续的代码中没有使用时,可以使用 boost::ignore_unused() 来避免编译器产生未使用变量的警告。
  3. 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <boost/core/ignore_unused.hpp>

    int main() {
    int x = 42;

    // 防止编译器警告,因为 y 没有在后续的代码中使用
    boost::ignore_unused(x);

    return 0;
    }

    在这个示例中,boost::ignore_unused(x) 告诉编译器忽略变量 x 的未使用警告。这在一些情况下很有用,例如在编写模板代码时,你可能有一些参数是在某些情况下使用的,但在其他情况下可能未使用。

总的来说,boost::ignore_unused() 是一个方便的宏,用于防止编译器因未使用变量而产生的警告。