从零开始开发 VS Code 插件之 Translator Helper

本文目录

  • Translator Helper 介绍

  • 开发概述

  • 创建第一个VS Code Extension

  • 需求分析

  • 操作文本

  • 调用Google Translation API

  • 实现核心功能

  • 配置命令

  • 插件配置

  • 测试插件

  • 打包插件

  • 发布插件

  • CI/CD

  • Icon及README

  • 小结

Translator Helper 介绍

微软 Docs 网站上线之后,我发现很多中文内容是由机器翻译的,可读性比较差。2017 年开始我参与了中文文档的本地化工作,对机器翻译的文本进行校对。Docs 的内容全部托管在 GitHub 上,参与者可以 fork 仓库后进行修改,然后提交 PR。在此过程中,我写了一个一键翻译的 VS Code Extension,极大的提高了翻译效率。圣诞节假期正好有空,完善了一下代码,并添加了图标、README 等内容,正式发布到 VS Code 的 Marketplace 里了。在此介绍一下该插件的开发过程,希望更多人能参与到本地化工作中,为其他开发者提供高质量的中文内容。

之前我写过一篇如何参与 Docs 本地化的文章,详见:如何向微软 Docs 和本地化社区提交翻译贡献

还有一篇文章介绍了这个插件的使用方式:提高文档翻译效率神器:VS Code 插件之 Translator Helper

在开发此插件之前,为了方便翻译,我一般是把段落复制到 Google 翻译里,翻译成中文复制粘贴过来,再手动修改。但选择>复制>粘贴的过程非常无趣,于是想找一个简单的方法自动完成这个动作。但是找遍了 VS Code Markedplace 里的翻译插件,大都是在状态栏提示翻译,或悬浮框显示翻译,没有一个能完成这个动作。于是只好自己动手写一个了。好在 VS Code 提供了非常完善的开发文档,我花了两三个小时就完成了主要功能的开发。其实对一个完善的插件来说,找 icon、写文档、做示例也相当费时间,于是拖到最近才正式发布。

我现在的做法是,同时开两个 VS Code,一个是英文原版的仓库,一个是中文仓库,两边对照看。使用 Translator Helper 可以一键翻译指定段落并插入到英文文本后面,人工校对修改一下即可,翻译效率大大提高。再也不用在 VS Code 和浏览器之间来回复制粘贴了。

将光标定位在一个段落的任意位置,按Alt+T,即可将当前段落自动翻译成中文并插入到该段落后面。

然后可以人工对部分语句进行调整即可。翻译后的文本也会自动选中,方便进行复制粘贴等操作。

使用了这个小工具后,翻译文档的速度大大提高了。

求五星好评啊 

开发概述

开发一个 VS Code Extension 并不难,但开发一个好的Extension不容易。让我们还是从Hello World开始吧。VS Code 官网提供了详细的开发文档:https://code.visualstudio.com/api。

首先我们要确定我们要实现的功能属于哪个分类:

  • Theming[1] :使用颜色或图标主题改变 VS Code 的外观

  • Extending the Workbench[2] :在 UI 中添加自定义组件、视图

  • Webview Guide[3]:创建 WebView 来显示 HTML/CSS/JS 构造的自定义页面

  • Language Extensions Overview[4]:支持新的编程语言

  • Debugger Extension Guide[5]:支持调试某种运行时

不同的分类在开发中有不同的侧重点,使用到的 API 也不一样。比如我们要实现的翻译功能,属于 Extending the Workbench 这一类。接下来给大家介绍一下Translator Helper是怎么开发出来的。

创建第一个Extension

可以在这里找到详细的入门教程:https://code.visualstudio.com/api/get-started/your-first-extension

首先,使用npm安装YeomanVS Code Extension Generator:

npm install -g yo generator-code

导航到要创建 Extension 的目录,使用如下命令创建项目:

yo code

CLI 会询问一些问题。第一个问题是这样的:

创建项目

这里要根据插件的具体功能来选择。对于我们的 hello world 项目,可以选择使用TypeScript来开发。完整的输入输出如下所示:

# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? HelloWorld
### Press <Enter> to choose default for all options below #### ? What's the identifier of your extension? helloworld
# ? What's the description of your extension? LEAVE BLANK
# ? Initialize a git repository? Yes
# ? Which package manager to use? npmcode ./helloworld

这样就创建了一个名为helloworld的 VS Code 插件,并使用 VS Code 打开了项目。可以直接按F5来运行,这样会打开一个新的加载了该插件的 VS Code 窗口。

F1Ctrl+Shift+P,输入Hello World命令,可以看到右下角弹出了一个消息框并显示Hello World。这说明插件已经正常工作了。

关键的代码都在extension.ts文件里。打开该文件看一下:

// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {// Use the console to output diagnostic information (console.log) and errors (console.error)// This line of code will only be executed once when your extension is activatedconsole.log('Congratulations, your extension "helloworld" is now active!');// The command has been defined in the package.json file// Now provide the implementation of the command with registerCommand// The commandId parameter must match the command field in package.jsonlet disposable = vscode.commands.registerCommand('extension.helloWorld', () => {// The code you place here will be executed every time your command is executed// Display a message box to the uservscode.window.showInformationMessage('Hello World!');});context.subscriptions.push(disposable);
}// this method is called when your extension is deactivated
export function deactivate() {}

代码很简单,就是使用vscode.commands.registerCommand()方法注册了一个命令,然后使用vscode.window.showInformationMessage()方法来显示右下角的消息框。

需求分析

我们的需求是,按某个快捷键,将当前段落翻译成中文,然后插入到该段落之后。让我们来查一下 VS Code支持的API。

在https://code.visualstudio.com/api/references/vscode-api这个页面可以查看所有VS Code 支持的 API。我们要操作当前的编辑器界面,实现自动选择段落、插入文本等操作,所以我找到了TextEditor这个对象:https://code.visualstudio.com/api/references/vscode-api#TextEditor:

TextEditor API

这个对象的属性和方法应该可以完成我们的工作。

这样思路就比较清楚了,注册快捷键和命令,选择当前光标所在的段落,发送文本到 Google 翻译 API 进行翻译,将返回的文本插入到段落之后。

操作文本

我封装了一个DocService来完成选择段落、插入文本等与编辑器操作相关的功能:

class DocService {editor: vscode.TextEditor | undefined;setCurrentEditor(): void {this.editor = vscode.window.activeTextEditor;}getParagraph(): string {if (this.editor !== undefined) {let startLine = this.editor.selection.start.line;let endLine = this.editor.selection.end.line;const endCharacter = this.editor.document.lineAt(endLine).text.length;this.editor.selection = new vscode.Selection(startLine, 0, startLine, endCharacter);var paragraph = this.editor.selection;let result = this.editor.document.getText(paragraph);if (result !== undefined) {return result;}else {return '';}} else {return '';}}getSelectionText(): string {if (this.editor !== undefined) {return this.editor.document.getText(this.editor.selection);} else {return '';}}insertText(text: string): void {if (this.editor !== undefined) {let end = this.editor.selection.end;this.editor.edit(editBuilder => {editBuilder.insert(end, '\n');editBuilder.insert(end, text);}).then(success => {if (success && this.editor !== undefined) {let end = this.editor.selection.end;this.editor.selection = new vscode.Selection(end, end);let startLine = this.editor.selection.start.line;let endLine = this.editor.selection.end.line;const endCharacter = this.editor.document.lineAt(endLine).text.length;this.editor.selection = new vscode.Selection(startLine, 0, startLine, endCharacter);}});}}

调用 Google Translation API

这个就是一般的发送 Http 请求了。可以使用一个 npm 包@vitalets/google-translate-api来实现。代码如下:

class GoogleTranslationService implements ITranslatorService {async translate(text: string, source: string, target: string): Promise<string> {const service = googleTranslate;let result = await service(text, { from: source, to: target });return result.text;}
}

实现核心功能

现在我们可以把这些功能组合起来了。照着 Hello World 例子里的代码抄一个:

	let translateInsert = vscode.commands.registerCommand('translatorHelper.translateInsert', async () => {// The code you place here will be executed every time your command is executeddocService.setCurrentEditor();const text = docService.getParagraph();try {if (text.trim() !== '') {let result = await servie.translate(text, source, target);docService.insertText(result);}} catch (error) {vscode.window.showErrorMessage(`Error occurs. ${error.message}`);}});

代码很容易理解,首先调用DocService获取当前段落,自动选择段落文本,然后发送到 Google 翻译 API,把返回的翻译文本插入到该段落之后。

配置命令

只在代码里注册命令是无法起作用的,我们还需要修改package.json文件来配置新添加的命令。VS Code 插件开发中有一个很重要的概念叫Contribution Points[6],详细的 API 可参考此文档:https://code.visualstudio.com/api/references/contribution-points。Contribution Points 是在package.json文件中的一系列配置,用来声明插件的一些属性,快捷键、配置项等也需要在这里进行配置。部分代码如下:

"activationEvents": ["onCommand:translatorHelper.translateInsert"]

以及:

    "contributes": {"commands": [{"command": "translatorHelper.translateInsert","title": "Translate & Insert"}],"keybindings": [{"command": "translatorHelper.translateInsert","key": "alt+t","when": "editorTextFocus"}],...

可以看到,我添加了名为translatorHelper.translateInsert的命令,与注册命令代码中的命令名称是一致的。同时还添加了一个keybindings,当按下Alt+T的时候会触发这个命令。

  • contributes.commands: https://code.visualstudio.com/api/references/contribution-points#contributes.commands

  • contributes.keybindings: https://code.visualstudio.com/api/references/contribution-points#contributes.keybindings

插件配置

翻译的语言应该是可配置的,因此我们需要添加几个配置项。需要用到的是contributes.configuration。VS Code 把所有插件的配置项统一进行管理,提供了统一的 API 来读取。在package.jsoncontributes节里添加如下代码:

"configuration": {"title": "Translator Helper","properties": {"translatorHelper.api": {"type": "string","default": "google","enum": ["google","google-cn"],"enumDescriptions": ["Google Translation API.","Google Translation API for Chinese users."],"description": "Specify the api to translate the text."},"translatorHelper.sourceLanguage": {"type": "string","default": "en","description": "The source language to be translated."},"translatorHelper.targetLanguage": {"type": "string","default": "zh-CN","description": "The target language."}}}

配置项可以是文本、枚举或其他类型,还可以设置默认值、给枚举添加描述等,这样在下拉列表框里就可以看到详细的枚举项描述。详细的配置方式可参考:https://code.visualstudio.com/api/references/contribution-points#contributes.configuration。

在代码中,使用如下方式读取配置:

	let config = vscode.workspace.getConfiguration("translatorHelper");const api = config.api;const source = config.sourceLanguage;const target = config.targetLanguage;

这样一个基本的插件就开发好了。实际效果如本文开头图片所示。

测试插件

在一个程序的完整开发流程中,测试也是重要的一个环节。在 DevOps 的整个流程中,良好的测试能够保证程序的功能质量。所以我们还需要添加测试。具体步骤可参考此文档:https://code.visualstudio.com/api/working-with-extensions/testing-extension。

默认的项目模板已经自带了完整的测试用例,存放在src/test目录下。所以我们只需要修改测试用例的部分代码即可。我在src/test/suite目录中,添加了一个默认的 markdown 文件test.md,里面写了个"Hello World"。在运行测试的时候,自动运行 VS Code 载入这个文件,并调用命令翻译。部分代码如下:

	test("Should get the correct translation then insert it.", async () => {const uri = vscode.Uri.file(path.join(__dirname + testFileLocation));const document = await vscode.workspace.openTextDocument(uri);const editor = await vscode.window.showTextDocument(document);// Make sure the file is fully loaded before interacting with it.await sleep(200);vscode.commands.executeCommand('extension.translateInsert').then(result => {assert.equal(editor.document.getText(editor.selection).indexOf('你好') > -1, true);});});

这段代码会自动载入文本,并调用该命令进行翻译,然后获取新插入的文本,对比翻译后的内容,符合要求即说明翻译功能正常。

打包插件

在我们开发前端应用时,都会使用某些打包工具压缩代码,减小体积。对于 VS Code 插件来说,这也是一个很重要的要求。载入大量零散的 js 文件速度会比较慢。VS Code 建议使用 webpack 来打包。详细过程可参考:https://code.visualstudio.com/api/working-with-extensions/bundling-extension

首先要安装 webpack:

npm i --save-dev webpack webpack-cli

还要安装ts-loader来让 webpack 支持 TypeScript:

npm i --save-dev ts-loader

安装 webpack 后会在项目中添加一个webpack.config.js文件。此外还要根据文档来修改package.json的内容,使用 webpack 来进行打包:

    "scripts": {"vscode:prepublish": "webpack --mode production","webpack": "webpack --mode development","webpack-dev": "webpack --mode development --watch","test-compile": "tsc -p ./","compile": "tsc -p ./","watch": "tsc -watch -p ./","pretest": "npm run compile","test": "node ./out/test/runTest.js","deploy": "vsce publish --yarn"},

有前端开发经验的同学应该比较熟悉了,此处不再赘述。

发布插件

在发布之前,要安装vsce工具。这是一个用来打包、发布、管理 VS Code 插件的一个命令行工具。使用以下命令安装:

npm install -g vsce

在正式发布之前,还需要在 Marketplace 中注册一个账户,获取 Access Token,才能用vsce来发布。注册方式可参考:https://code.visualstudio.com/api/working-with-extensions/publishing-extension

后面的步骤还有创建 publisher 等。因为文档已经详细描述了过程,此处就不复制了。需要注意,如果没有创建 Publisher 的话,直接使用命令发布是无法成功的。

CI/CD

每次手工发布还是比较繁琐的,最好集成 Azure DevOps 来做 CI/CD。可以参考此文档来建立 Pipeline:https://code.visualstudio.com/api/working-with-extensions/continuous-integration。

这里需要注意的是,我们需要用到 Access Token 来进行发布,但这是一个敏感信息,所以需要在 Pipeline 里创建一个 Variable 来保存这个 Token,再在 YAML 文件里调用。

在Pipeline中创建Variable

YAML 代码如下:

trigger:branches:include: ['master']tags:include: ['*']strategy:matrix:linux:imageName: 'ubuntu-16.04'mac:imageName: 'macos-10.13'windows:imageName: 'vs2017-win2016'pool:vmImage: $(imageName)steps:- task: NodeTool@0inputs:versionSpec: '8.x'displayName: 'Install Node.js'- bash: |/usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &echo ">>> Started xvfb"displayName: Start xvfbcondition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))- bash: |echo ">>> Compile vscode-test"yarn && yarn compileecho ">>> Compiled vscode-test"cd sampleecho ">>> Run sample integration test"yarn && yarn compile && yarn testdisplayName: Run Testsenv:DISPLAY: ':99.0'- bash: |echo ">>> Publish"yarn deploy -p $(VSCODE_MARKETPLACE_TOKEN)displayName: Publishcondition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))

这里使用了$(VSCODE_MARKETPLACE_TOKEN)来获取 Access Token的值。在trigger这样我们就实现了使用 Azure DevOps 来做自动发布,每次提交更改后,Pipelines 会自动编译,并发布到 Marketplace。

Icon 及 README

哦还有很重要的一个,插件的图标及 README 也是必须的。推荐一个免费工具Lunacy,在 Windows 10 商店里就可以下载,这个工具自带了一些图标,还可以下载包含 10 万多个图标的扩展包,足够你挑一个了:

Lunacy支持下载图标扩展包

将做好的icon文件放到项目目录里,在package.json文件中进行配置:

"icon": "images/icon.png",

此外,还需要在package.json中定义插件的id、显示名称、描述、版本、发布者、仓库地址、支持的VS Code版本、插件类别等等。还可以给插件添加几个badges,用来显示插件的各种状态,如Pipelines的编译状态、当前版本、下载量、评分等等。因为都比较直观,就不贴文件内容了。可参考此文档:https://code.visualstudio.com/api/references/extension-manifest

README 文件会显示在 Marketplace 的插件页面上,要修改自带的README文件模板详细说明插件的作用、使用方法、配置项等,最好制作几个 Gif 动画来展示插件可以做什么。制作 Gif 动画的工具很多,可自行搜索。我使用的是 SNAGIT。

小结

这只是一个非常非常简单的 VS Code 插件,但确实提高了我的工作效率。我还开发了一个支持 Word 的翻译插件,思路也是一样的。当手边没有趁手的工具时,何不自己打造一个呢,开发的过程还是非常有乐趣的。希望大家下载插件试用一下,给个五星好评就更好了哈哈 O(∩_∩)O 另外该项目也开源在 GitHub 了:https://github.com/yanxiaodi/vscode-translator-helper。欢迎加星啊

下一步计划是支持微软的Cognitive Services API,如果有兴趣的话欢迎参与,一起改进这个项目。

最后希望大家可以关注我的公众号:程序员在新西兰,了解新西兰码农的真实生活。感谢大家阅读。

了解新西兰IT行业真实码农生活
请长按上方二维码关注“程序员在新西兰”

推荐阅读

  • 如何向微软 Docs 和本地化社区提交翻译贡献

  • 提高文档翻译效率神器:VS Code 插件之 Translator Helper

  • 为WPF, UWP 及 Xamarin实现一个简单的消息组件

  • 【手把手教程】如何让你的求职简历敲开新西兰雇主的大门(文末送福利)

  • 再不拼老命我们就真老了——大龄码农DIY新西兰技术移民全记录

  • 移民路上为什么别人总能得到更多的信息,今天知道真相还不算太晚

  • 雅思之路——只有绝境没有捷径

  • 身在中国,如何应对海外公司的电话面试?

参考资料

[1]

Theming: https://code.visualstudio.com/api/extension-capabilities/theming

[2]

Extending the Workbench: https://code.visualstudio.com/api/extension-capabilities/extending-workbench

[3]

Webview Guide: https://code.visualstudio.com/api/extension-guides/webview

[4]

Language Extensions Overview: https://code.visualstudio.com/api/language-extensions/overview

[5]

Debugger Extension Guide: https://code.visualstudio.com/api/extension-guides/debugger-extension

[6]

Contribution Points: https://code.visualstudio.com/api/references/contribution-points

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312284.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【实战 Ids4】║ 又一个项目迁移完成(MVC)

迎周一&#xff0c;腊月十九&#xff0c;小年倒计时新年还有两周时间就要到了&#xff0c;学习可不能停&#xff0c;这几天一直在加班调休&#xff0c;周末也如此&#xff0c;不过也是趁着半夜凌晨的时间&#xff0c;继续迁移我的项目到IdentityServer4统一认证授权中心Blog.Id…

C++string容器-赋值操作

功能描述&#xff1a; 给string字符串进行赋值 代码如下&#xff1a; #include <iostream> using namespace std; #include <cstring>void test01() {string str1;str1 "hello world";cout << "str1 " << str1 << endl;…

为什么说云原生会成为未来企业技术变迁的趋势

云原生是当下的热点话题&#xff0c;但是很多人对云原生有很多误解&#xff0c;特别是传统产业物联网或工控、物联网行业对云原生显得"后知后觉"。与其在这里说是预测&#xff0c;不如说是现在进行时&#xff0c;只是由于传统产业本身的技术包袱和组织个人认识程度差…

C++vector容器-构造函数

vector数据结构和数组非常相似&#xff0c;也称为单端数组&#xff0c;在数组的尾段可以做插入&#xff0c;删除操作 vector不同于普通数组&#xff0c;vector可以动态扩展 动态扩展&#xff1a;并不是在原空间之后续接新空间&#xff0c;而是找更大的内存空间&#xff0c;然…

BeetleX网关之请求聚合

在网关服务中请求聚合是允许把多个请求打包成一个响应给请求方&#xff0c;这样不仅可以节省请求方的请求数量&#xff0c;还可以根据需求的情况整合不同业务数据响应请求。BeetleX.Bumblebee虽然并没有内置这一功能&#xff0c;但可以通过扩展的形式来支持请求聚合&#xff0c…

C++vector容器-赋值操作

vector赋值操作 功能描述&#xff1a; 给vector容器进行赋值 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector> //vector赋值操作void printVector(vector<int> &v) {for (vector<int >…

EntityFramework Core表名原理解析,让我来,揭开你神秘的面纱

上一节我们针对最开始抛出的异常只是进行了浅尝辄止的解析&#xff0c;是不是有点意犹未尽的感觉&#xff0c;是的&#xff0c;我也有这种感觉&#xff0c;看到这里相信您和我会有一些疑惑&#xff0c;要是我们接下来通过注解、Fluent APi、DbSet分别对表名进行如下设置&#x…

C++vector容器-容量和大小

vector容量和大小 功能描述&#xff1a; 对vector容器的容量和大小操作 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector> //vector容器的容量和大小操作void printVector(vector<int > &v) {…

openresty+mysql+乱码_openresty记录响应body乱码问题

问题背景最近新上了一个功能&#xff0c;openresty通过syslog记录请求日志&#xff0c;然后由logstash推送至ES。测试上线时未发现这个问题&#xff0c;在日常查看日志的过程中&#xff0c;发现logstash推送有错误日志&#xff0c;错误内容为&#xff1a;Error parsing json&am…

【Azure学习.01】先从账号注册开始

本文部分内容配套视频&#xff1a;https://www.bilibili.com/video/av82898957马上要放假了&#xff0c;决定在家里简单了解一下Azure云服务&#xff0c;虽然公司其他部分用到了这个Azure&#xff0c;但是我还是没有接触到&#xff0c;只是听说很贵&#xff0c;好几千每天&…

C++vector容器-插入和删除

vector插入和删除 功能描述&#xff1a; 对vector容器进行插入&#xff0c;删除操作 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector> //vector插入和删除void printVector(vector<int > &v…

C++vector容器-数据存取

vector数据存取 功能描述&#xff1a; 对vector中的数据的存取操作 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector>//vector容器 数据存取 void test01() {vector<int >v1;for (int i 0; i &l…

如何快速融入团队(四)

作者&#xff1a;邹溪源&#xff0c;长沙资深互联网从业者&#xff0c;架构师社区特邀嘉宾&#xff01;01不知不觉这个系列已经开始第四篇的&#xff0c;其实我的原始意图只是思考一下如果有幸加入一个新团队&#xff0c;我们在思想和行动上该做哪些准备呢。不过随着内容的逐渐…

C++vector容器-互换容器

vector容器互换 功能描述&#xff1a; 实现两个容器内元素进行互换 函数原型&#xff1a; swap(vec);//将vec与本身的元素互换 1.基本使用 代码如下: #include <iostream> using namespace std; //vector容器互换 #include <vector> //1.基本使用void printVect…

.NET 状态机Automatonymous快速入门

介绍 Automatonymous是.NET开发人员的状态机库。它提供了一种流畅的语法来声明状态机&#xff0c;包括状态&#xff0c;事件&#xff08;支持触发器和数据事件&#xff09;以及状态/事件活动。尽管Automatonymous在简单的状态机上非常容易使用&#xff0c;但它具有许多高级功能…

BeetleX实现HTTP协议详解

在传统网络服务中扩展中需要处理Bytes来进行协议的读写&#xff0c;这种原始的处理方式让工作变得相当繁琐复杂&#xff0c;出错和调试的工作量都非常大&#xff1b;组件为了解决这一问题引用Stream读写方式&#xff0c;这种方式可以极大的简化网络协议读写的工作量&#xff0c…

euclidea4攻略_Euclidea几何构建11.4通关攻略

Euclidea几何构建10.2通关攻略Euclidea游戏10.2怎么过&#xff1f;下面小编为大家带来Euclidea几何构建10.2通关攻略&#xff1a;更多攻略不断更新中——Euclidea游戏全关卡通关攻略大全分两次做图第一次&#xff0c;画圆就成了&#xff0c;具体看图应该能懂。第二次&#xff0…

C++set容器-构造和赋值

set基本概念 简介&#xff1a; 所有元素都会自动在插入时自动被排序&#xff0c;set容器也叫集合容器 本质&#xff1a; set/multiset属于关联式容器&#xff0c;底层结构是用二叉树排序 set和multiset区别&#xff1a; 1.set不允许容器中有重复的元素 2.multiset允许容器中有…

(1)解锁MongoDB replica set核心姿势

本文倒腾目前大热的MongoDB Replica Set集群&#xff0c;在倒腾的同时串讲一些 MongoDB特性。 副本集Replica Set是一个术语&#xff0c;定义具有多节点的数据库集群&#xff0c;这些节点具有主从复制(master-slave replication) 且节点之间实现了自动故障转移。 这样的结构通常…

java写dnf外掛_dnf卡盟_Java的泛型详解(一)

Java实现DDD中UnitOfWorkdnf卡盟Java的泛型详解泛型的利益编写的代码可以被差别类型的工具所重用。由于上面的一个优点&#xff0c;泛型也可以削减代码的编写。泛型的使用简朴泛型类public class Pair {private T first;private T second;public Pair() {first null;second n…