当前位置: 首页 > 编程日记 > 正文

基于Golang的对象序列化的程序包开发——myJsonMarshal

基于Golang的对象序列化的程序包开发——myJsonMarshal【阅读时间:约10分钟】

  • 一、对象序列化概述
  • 二、系统环境&项目介绍
    • 1.系统环境
    • 2.项目的任务要求
  • 三、具体程序设计及Golang代码实现
    • 1.程序设计
    • 2.JsonMarshal函数
    • 3.Marshal函数
    • 4.StringTrans函数
    • 5.StructTrans函数
    • 6.MapTrans函数
    • 7.SliceTrans函数
    • 8.ArrayTrans函数
    • 9.PtrTrans函数
  • 四、程序测试
    • 1.封装并使用程序包
    • 2.功能测试
    • 3.单元测试
  • 五、中文 api 文档
  • 六、完整代码
  • 七、References

一、对象序列化概述

将一个对象写成特定文本格式的字符流,称为序列化。在本次开发的程序包myJsonMarshal中,我们可以利用它将将结构数据格式化为 json 字符流。


二、系统环境&项目介绍

1.系统环境

操作系统:CentOS7
硬件信息:使用virtual box配置虚拟机(内存3G、磁盘30G)
编程语言:GO 1.15.2

2.项目的任务要求

  1. 参考官方 encoding/json 包 Marshal 函数,将结构数据格式化为 json 字符流
    • 必须导出 func JsonMarshal(v interface{}) ([]byte, error)
    • 可以参考、甚至复制原来的代码
    • 支持字段的标签(Tag),标签满足 mytag:"你自己的定义"
    • 不允许使用第三方包
  2. 包必须包括以下内容:
    • 生成的中文 api 文档
    • 有较好的 Readme 文件,包括一个简单的使用案例
    • 每个go文件必须有对应的测试文件



三、具体程序设计及Golang代码实现

1.程序设计

本次程序包开发实现较为简单,只要根据输入的结构数据的类型,逐步分为多种基础的类型,如int、string和array等,然后将输入数据及其类型转为byte[],再转为json格式的字符流即可。
其中,参考官方 encoding/json 包 Marshal 函数,在判断数据类型时用到了reflect程序包。
myJsonMarshal程序包的函数架构如下:
在这里插入图片描述
下面按照myJsonMarshal程序包的源码顺序来依次介绍数据结构和相关函数。

2.JsonMarshal函数

//JsonMarshal 输入结构化数据,返回json字符流和error
func JsonMarshal(v interface{}) ([]byte, error) {b, err := Marshal(v)if err != nil {return nil, err}return b, nil
}

JsonMarshal函数是本程序包的主要接口,通过输入结构化数据,可以返回json字符流和报错信息error。


3.Marshal函数

//Marshal 将接口数据类型的数据转为json字符流
func Marshal(v interface{}) ([]byte, error) {json := reflect.ValueOf(v)typeJson := json.Type()switch typeJson.Kind() {case reflect.Invalid:return []byte("Invalid"), errors.New("Invalid")case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,reflect.Uint64, reflect.Float32, reflect.Float64:return []byte(fmt.Sprintf("%v", json.Interface())), nilcase reflect.String:return StringTrans(v)case reflect.Struct:return StructTrans(v)case reflect.Map:return MapTrans(v)case reflect.Slice:return SliceTrans(v)case reflect.Array:return ArrayTrans(v)case reflect.Ptr:return PtrTrans(v)default:return []byte("unsupportedTypeTrans"), errors.New("unsupportedTypeTrans")}
}

Marshal函数调用reflect程序包,通过switch-case语句,将不同接口数据类型的数据转为json字符流。



4.StringTrans函数

//StringTrans 将string数据转为json字符流
func StringTrans(v interface{}) ([]byte, error) {json := reflect.ValueOf(v)return []byte("\"" + json.String() + "\""), nil
}

StringTrans函数将string数据转为json字符流


5.StructTrans函数

//StructTrans 将struct数据转为json字符流
func StructTrans(v interface{}) ([]byte, error) {json := reflect.ValueOf(v)typeJson := json.Type()b := "{"for i := 0; i < json.NumField(); i++ {if i > 0 {b = b + ","}tag := typeJson.Field(i).Tag.Get("mytag")if tag == "" {b = b + "\"" + typeJson.Field(i).Name + "\":"} else {b = b + "\"" + tag + "\":"}tmp, err := Marshal(json.Field(i).Interface())if err != nil {return nil, err}b = b + string(tmp)}b = b + "}"return []byte(b), nil
}

StructTrans函数将struct数据转为json字符流,并且支持字段的标签(Tag),标签满足 mytag:"你自己的定义"。如果变量打上了mytag标签,如Name旁边的 mytag:"name" ,那么转化成的json key就用该标签“name”,否则取变量名作为key。


6.MapTrans函数

//MapTrans 将map数据转为json字符流
func MapTrans(v interface{}) ([]byte, error) {json := reflect.ValueOf(v)i := json.MapRange()first := trueb := "{"for i.Next() {if first {first = false} else {b = b + ","}b = b + "\"" + fmt.Sprintf("\"%v\":", i.Key()) + "\":"tmp, err := Marshal(i.Value().Interface())if err != nil {return nil, err}b = b + string(tmp)}b = b + "}"return []byte(b), nil
}

MapTrans函数将map数据转为json字符流


7.SliceTrans函数

//SliceTrans 将slice数据转为json字符流
func SliceTrans(v interface{}) ([]byte, error) {json := reflect.ValueOf(v)b := "["for i := 0; i < json.Len(); i++ {if i > 0 {b = b + ","}tmp, err := Marshal(json.Index(i).Interface())if err != nil {return nil, err}b = b + string(tmp)}b = b + "]"return []byte(b), nil
}

SliceTrans函数将slice数据转为json字符流



8.ArrayTrans函数

//ArrayTrans 将array数据转为json字符流
func ArrayTrans(v interface{}) ([]byte, error) {json := reflect.ValueOf(v)b := "["for i := 0; i < json.Len(); i++ {if i > 0 {b = b + ","}tmp, err := Marshal(json.Index(i).Interface())if err != nil {return nil, err}b = b + string(tmp)}b = b + "]"return []byte(b), nil
}

ArrayTrans函数将array数据转为json字符流


9.PtrTrans函数

//PtrTrans 将ptr数据转为json字符流
func PtrTrans(v interface{}) ([]byte, error) {json := reflect.ValueOf(v)return Marshal(json.Elem().Interface())
}

StringTrans函数将ptr数据转为json字符流,指针变量编码时自动转换为它所指向的值。



四、程序测试

1.封装并使用程序包

将项目myJsonMarshal的myJsonMarshal.go文件的main函数注释掉,package改为package myJsonMarshal,然后执行如下指令:

go build

在其他路径下建立main.go,并调用myJsonMarshal.JsonMarshal函数即可。



2.功能测试

功能测试主要从用户角度测试程序包的功能,步骤如下:
创建main.go文件,内容如下(结构化数据类型及其数值可自定义):

package mainimport ("fmt""github.com/user/myJsonMarshal"
)type Stu struct {Name  string `mytag:"name"`Age   intHIgh  boolClass *Class `mytag:"class"`
}type Class struct {Name  stringGrade int
}func main() {//实例化一个数据结构,用于生成json字符串stu := Stu{Name: "张三",Age:  18,HIgh: true,}//指针变量cla := new(Class)cla.Name = "1班"cla.Grade = 3stu.Class = cla//Marshal失败时err!=niljsonStu, err := myJsonMarshal.JsonMarshal(stu)if err != nil {fmt.Println("生成json字符串错误")}//jsonStu是[]byte类型,转化成string类型便于查看fmt.Println(string(jsonStu))
}

运行结果:
在这里插入图片描述
由此可知程序包的功能测试正常,符合的程序包的几个要求:
①结构化数据转为json字符流
②支持字段的标签(Tag),标签满足 mytag:"你自己的定义"
③指针变量编码时自动转换为它所指向的值



3.单元测试

单元测试主要从程序员角度,对程序包的具体函数进行测试。
建立myJsonMarshal_test.go文件,对程序包的每个函数进行单元测试如下,代码如下:

package myJsonMarshalimport ("fmt""testing"
)type Stu struct {Name  string `mytag:"name"`Age   intHIgh  boolClass *Class `mytag:"class"`
}type Class struct {Name  stringGrade int
}func Test_JsonMarshal(t *testing.T) {//实例化一个数据结构,用于生成json字符串stu := Stu{Name: "张三",Age:  18,HIgh: true,}//指针变量cla := new(Class)cla.Name = "1班"cla.Grade = 3stu.Class = cla//Marshal失败时err!=niljsonStu, err := JsonMarshal(stu)if err != nil {fmt.Println("生成json字符串错误")}want := "{\"name\":\"张三\",\"Age\":18,\"HIgh\":true,\"class\":{\"Name\":\"1班\",\"Grade\":3}}"got := string(jsonStu)if got != want {t.Errorf("\n got %s\n want %s\n", got, want)}
}func Test_Marshal(t *testing.T) {//实例化一个数据结构,用于生成json字符串stu := Stu{Name: "张三",Age:  18,HIgh: true,}//指针变量cla := new(Class)cla.Name = "1班"cla.Grade = 3stu.Class = cla//Marshal失败时err!=niljsonStu, err := Marshal(stu)if err != nil {fmt.Println("生成json字符串错误")}want := "{\"name\":\"张三\",\"Age\":18,\"HIgh\":true,\"class\":{\"Name\":\"1班\",\"Grade\":3}}"got := string(jsonStu)if got != want {t.Errorf("\n got %s\n want %s\n", got, want)}
}func Test_StringTrans(t *testing.T) {//实例化一个数据结构,用于生成json字符串test := "unit test"//Marshal失败时err!=niljsonStu, err := StringTrans(test)if err != nil {fmt.Println("生成json字符串错误")}want := "\"unit test\""got := string(jsonStu)if got != want {t.Errorf("\n got %s\n want %s\n", got, want)}
}func Test_StructTrans(t *testing.T) {//实例化一个数据结构,用于生成json字符串test := Class{Name:  "1班",Grade: 3,}//Marshal失败时err!=niljsonStu, err := StructTrans(test)if err != nil {fmt.Println("生成json字符串错误")}want := "{\"Name\":\"1班\",\"Grade\":3}"got := string(jsonStu)if got != want {t.Errorf("\n got %s\n want %s\n", got, want)}
}func Test_MapTrans(t *testing.T) {//实例化一个数据结构,用于生成json字符串test := map[string]int{"one":   1,"two":   2,"three": 3,}//Marshal失败时err!=niljsonStu, err := MapTrans(test)if err != nil {fmt.Println("生成json字符串错误")}want := "{\"\"one\":\":1,\"\"two\":\":2,\"\"three\":\":3}"got := string(jsonStu)if got != want {t.Errorf("\n got %s\n want %s\n", got, want)}
}func Test_SliceTrans(t *testing.T) {//实例化一个数据结构,用于生成json字符串test := []int{1, 2, 3}//Marshal失败时err!=niljsonStu, err := SliceTrans(test)if err != nil {fmt.Println("生成json字符串错误")}want := "[1,2,3]"got := string(jsonStu)if got != want {t.Errorf("\n got %s\n want %s\n", got, want)}
}func Test_ArrayTrans(t *testing.T) {//实例化一个数据结构,用于生成json字符串test := [3]int{1, 2, 3}//Marshal失败时err!=niljsonStu, err := ArrayTrans(test)if err != nil {fmt.Println("生成json字符串错误")}want := "[1,2,3]"got := string(jsonStu)if got != want {t.Errorf("\n got %s\n want %s\n", got, want)}
}func Test_PtrTrans(t *testing.T) {//实例化一个数据结构,用于生成json字符串test := new(Class)test.Name = "1班"test.Grade = 3//Marshal失败时err!=niljsonStu, err := PtrTrans(test)if err != nil {fmt.Println("生成json字符串错误")}want := "{\"Name\":\"1班\",\"Grade\":3}"got := string(jsonStu)if got != want {t.Errorf("\n got %s\n want %s\n", got, want)}
}

在执行单元测试时,我们可以像上一次博客一样【博客】,在vscode中便捷地对每个函数进行test run,当编写单个函数的测试函数时,笔者更推荐这种方式。
当然,也可以像本次博客一样,在项目目录下,输入以下指令:

go test -v myJsonMarshal_test.go myJsonMarshal.go 

单元测试结果如下:

[henryhzy@localhost myJsonMarshal]$ go test -v myJsonMarshal_test.go myJsonMarshal.go 
=== RUN   Test_JsonMarshal
--- PASS: Test_JsonMarshal (0.00s)
=== RUN   Test_Marshal
--- PASS: Test_Marshal (0.00s)
=== RUN   Test_StringTrans
--- PASS: Test_StringTrans (0.00s)
=== RUN   Test_StructTrans
--- PASS: Test_StructTrans (0.00s)
=== RUN   Test_MapTrans
--- PASS: Test_MapTrans (0.00s)
=== RUN   Test_SliceTrans
--- PASS: Test_SliceTrans (0.00s)
=== RUN   Test_ArrayTrans
--- PASS: Test_ArrayTrans (0.00s)
=== RUN   Test_PtrTrans
--- PASS: Test_PtrTrans (0.00s)
PASS
ok  	command-line-arguments	0.002s

在这里插入图片描述



五、中文 api 文档

首先安装godoc如下:

git clone https://github.com/golang/tools $GOPATH/src/golang.org/x/tools
go build golang.org/x/tools

在项目myJsonMarshal所在目录下,执行如下指令:

go install
go doc
godoc -url="pkg/github.com/user/myJsonMarshal" > API.html

在这里插入图片描述

便会在当前目录下生成API.html文件:
在这里插入图片描述

【注意:程序包的函数名开头应为大写字母,对于函数A若含有注释,注释的开头也应为//A。】



六、完整代码

具体代码可见gitee仓库:gitee


七、References

  1. 课程博客
  2. go json.Marshal 编组函数讲解
  3. 官方 encoding/json 包

相关文章:

【golang程序包推荐分享】分享亿点点golang json操作及myJsonMarshal程序包开发的踩坑经历 :)

目录【阅读时间&#xff1a;约5分钟】一.概述1.Json的作用2.Go官方 encoding/json 包3. golang json的主要操作二.Json Marshal&#xff1a;将数据编码成json字符串三.Json Unmarshal&#xff1a;将json字符串解码到相应的数据结构四.myJsonMarshal程序包开发的踩坑经历1.go do…

Java数据结构和算法的数组

阵列的功能&#xff1a; 1、固定大小 2、相同的数据类型 3、 4、数据项可反复 Java数据类型&#xff1a;基本类型&#xff08;int和double&#xff09;和对象类型。在很多编程语言中。数组也是基本类型。但在Java中把它们当作对象来对待。因此在创建数组时必须使用new操作符。 …

玻璃和水晶PBR纹理材质预设

CGAxis–物理6–玻璃和水晶PBR纹理材质预设 大小&#xff1a;20.8G 信息: 透明玻璃、彩色玻璃和水晶的100种不同图案和变化的PBR纹理。这个包中的每个纹理由八个贴图组成:漫反射&#xff0c;反射&#xff0c;高度(位移)&#xff0c;光泽度&#xff0c;环境遮挡&#xff0c;金属…

【POJ1113】Wall(凸包)

【题目】 Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall around the Kings castle. The King was so greedy, that he would not listen to his Architects proposals to build a beautiful brick wall with a perfe…

matlab小波分析工具箱原理与应用_补充:频域特征值提取的MATLAB代码实现(小波分析)...

之前的文章信号频域分析方法的理解&#xff08;频谱、能量谱、功率谱、倒频谱、小波分析&#xff09;中提到了离散小波分解的例子&#xff0c;其参考代码如下&#xff1a;t_s 结果如下&#xff1a;原始信号离散小波分析结果左侧四行是1~4阶的近似信号&#xff0c;右侧四行是1~4…

【ReactiveX】基于Golang pmlpml/RxGo程序包的二次开发

基于Golang pmlpml/RxGo程序包的二次开发【阅读时间&#xff1a;约20分钟】一、ReactiveX & RxGo介绍1.ReactiveX2.RxGo二、系统环境&项目介绍1.系统环境2.项目的任务要求三、具体程序设计及Golang代码实现1.程序设计2.filteringOperator数据结构、op函数与newFilterOb…

python dataframe 中位数_python下的Pandas中DataFrame基本操作(一),基本函数整理

pandas作者Wes McKinney 在【PYTHON FOR DATA ANALYSIS】中对pandas的方方面面都有了一个权威简明的入门级的介绍&#xff0c;但在实际使用过程中&#xff0c;我发现书中的内容还只是冰山一角。谈到pandas数据的行更新、表合并等操作&#xff0c;一般用到的方法有concat、join、…

对输入框以及选择框集体的数据检验

对于一个档案输入框&#xff0c;有很多输入框是需要输入数据的&#xff0c;但有时候我们会在输入的时候遗留一些必填的项&#xff0c;如果不做数据校验&#xff0c;这时候点击保存按钮&#xff0c;就悲剧了&#xff0c;报错不说&#xff0c;我们前面填写的数据也就没有了。 所以…

CentOS Docker安装配置部署Golang web helloworld

目录【阅读时间&#xff1a;约5分钟】一、Docker简介二、Docker的安装与配置【CentOS环境】三、Docker部署Golang web helloworld四、Docker与虚拟机的区别五、吐槽一、Docker简介 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移…

[CareerCup] 2.4 Partition List 划分链表

2.4 Write code to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. LeetCode上的原题&#xff0c;请参见我之前的博客Partition List 划分链表。

一条命令下载google壁纸,含错误解决方法

该命令是从google图片搜索上搜索wallpaper的大尺寸图片&#xff0c;匹配其中的jpg文件进行下载。 #!/bin/bash for i in {1..10}; do for url in $(wget -O- -U "" "http://images.google.com/images?imgszxxlarge&hlen&qwallpaper&saN&s…

git config —global_Git多用户配置

备注&#xff1a;如下的操作&#xff0c;Windows系统建议在Git bash工具里操作。如下操作的原理&#xff0c;建议查阅官方文档。Git - Reference1.取消全局设置的用户信息。Git命令&#xff1a;$ git config --global --unset user.name $ git config --global --unset user.em…

中级实训总结报告

目录【阅读时间&#xff1a;约30分钟】中级实训总结报告姓名&#xff1a;隐藏敏感信息 学号&#xff1a;隐藏敏感信息一、阶段1&#xff1a;项目启动1、Vi/Vim2、Java3、Ant4、Junit5、SonarQube6、 编译运行BugRunner二、阶段2&#xff1a;基本任务1. part2的工作&#xff08;…

PHP解决方案@黑名单过滤

为什么80%的码农都做不了架构师&#xff1f;>>> 方案解决目标&#xff1a;对一些黑名单进行过滤处理 function is_spam($text, $file, $split :, $regex false){ $handle fopen($file,rb); $contents fread($handle, filesize($file)); fclose($handle); $lines …

Ubuntu 12.04下玩转终端管理器Byobu

简介 很多Linux高手都喜欢使用screen命令&#xff0c;screen命令可以使你轻松地使用一个终端控制其他终端。尽管screen本身是一个非常有用的工具&#xff0c;byobu作为screen的增强版本&#xff0c;比screen更加好用而且美观&#xff0c;并且提供有用的信息和快捷的热键。 想象…

python字典排序方法_Python字典的排序方法一则

今天需要对Python的字典进行排序&#xff0c;以获得有效的时间序列&#xff0c;采用了如下方法&#xff1a; 首先生成一个示例字典&#xff1a; >>> range_a random.sample(range(0, 10), 10) >>> range_b random.sample(range(10, 20), 10) >>> …

encodeURI 和 encodeURIComponent

保留字符 &#xff08;reserved characters&#xff09;&#xff1a;这类字符是URI中的保留关键字符&#xff0c;它们用于分割URI中的各个部分。这些字符是&#xff1a;";" | "/" | "?" | ":" | "" | "&&quo…

基于Golang的简单web服务程序开发——CloudGo

基于Golang的简单web服务程序开发——CloudGo【阅读时间&#xff1a;约10分钟】一、概述二、系统环境&项目介绍1.系统环境2.项目的任务要求&#xff08;1&#xff09;基本要求&#xff08;2&#xff09;扩展要求三、具体程序设计及Golang代码实现1.预先准备2.CloudGoClient…

Android Studio创建项目

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 https://blog.csdn.net/u010046908/article/details/47000873 创建项目 首先&#xff0c;先指出Android Studio中的两个概念。 Project和 Module。在Android Studio中&#xff0c; Project的真实含义…

Weiss的数据结构与算法分析(C++版)源码编译说明

最近尝试编译Weiss的那本数据结构与算法分析&#xff08;C版&#xff09;提供的源代码时&#xff0c;遇到一些问题&#xff0c;特记录如下&#xff1a;考虑到该书提供的代码是使用模板技术较多&#xff0c;这在提供简洁代码的同时&#xff0c;也给源码的编译带来了一些问题。因…

latex 中文_【小白向】LaTeX 中文入门

注&#xff1a;本文尚未撰写完毕&#xff0c;先暂存一下~(2020/06/27)参考学习路线[1]如何从零开始&#xff0c;入门 LaTeX&#xff1f; 孟晨 1. 卸载 CTeX 套装&#xff0c;安装 TeX Live原因及教程见&#xff1a;TeX Live 下载及安装说明2. 看完&#xff1a;一份其实很短的 L…

物联网兴起 嵌入式系统安全日益受关注

随着越来越多设备连接到互联网&#xff0c;专家们担心嵌入式系统将给企业带来严重安全风险&#xff0c;而很多企业还没有意识到这种风险或者无法缓解这种风险…… 随着越来越多设备连接到互联网&#xff0c;专家们担心嵌入式系统将给企业带来严重安全风险&#xff0c;而很多企业…

【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

目录【阅读时间&#xff1a;约10分钟】一.概述二.对比: gorilla/mux与net/http DefaultServeMux三.简单使用四.源码简析1.NewRouter函数2.HandleFunc函数设置路由的HTTP方法设置路由的域名限制HTTP 方案设置路径前缀和子路由3.PathPrefix函数五.References一.概述 gorilla/mux…

FileMaker中的腳本觸發器學習筆記

脚本触发器 **脚本触发器是始终绑定到用户布局接口。对于数据表或者字段。只有在而已接口才能触发。**如果某一个布局或者对象上包含触发器&#xff0c;则其右下角会有触发器图标**当触发一个事件时&#xff0c;有且仅有一个触发器会被执行.布局级别的触发器**ONRECORDLOAD :加…

vim学习笔记(四)

下面是我的最近更新&#xff0c;差点删除。 下面的笔记摘自vimtutor。<CR>表示回车 删除命令 在normal模式下&#xff1a; de 删除一个单词&#xff0c;不包含空格 dw 删除一个单词&#xff0c;包含空格 dd 删除当前行 1,10d 删除指定行&#xff0c;第1到10行 ndd…

文件和缓存项目依赖

文件和缓存项目依赖 要创建缓存依赖&#xff0c;你需要创建一个 CacheDependency 对象并在添加依赖的缓存项目时使用它。例如&#xff0c;下面的代码创建一个缓存项目&#xff0c;它在一个 XML 文件被修改、删除、覆盖时自动从缓存中移除&#xff1a; CacheDependency prodDepe…

python函数的基础知识_Python入门基础知识点(函数进阶)

动态参数&#xff1a; 动态接收位置参数&#xff1a; def eat(*args): #在形参位置&#xff0c;*叫做聚合 print(我想吃,args) eat(大米饭,中米饭,小米饭) #收到的结果是一个tuple元祖 动态接收参数的时候要注意: 动态参数必须在位置参数后面&#xff0c;否则&#xff1a; def …

【CentOS】利用Kubeadm部署Kubernetes (K8s)

【CentOS】利用Kubeadm部署Kubernetes &#xff08;K8s&#xff09;【阅读时间&#xff1a;约10分钟】一、概述二、系统环境&项目介绍1.系统环境2.项目的任务要求三、具体实验流程1 系统准备2 安装常用包3 使用aliyun源安装docker-ce4 安装kubectl、kubelet、kubeadm5 初始…

HttpClient4.4 登录知乎(详细过程)

引言 HttpClient是java语言下一个支持http协议的客户端编程工具包&#xff0c;它实现了HTTP协议的所有方法&#xff0c;但是不支持JS渲染。我们在做一些小玩意时&#xff0c;有可能需要登录某些网站获取信息&#xff0c;那么HttpClient就是你的好帮手&#xff0c;废话不多说&am…

vim学习笔记(一)

&#xff1a;vertical sfind 垂直分隔窗口(vsf)&#xff0c;但是两个窗口的内容完全相同。在编辑的时候&#xff0c;内容也完全相同&#xff0c;如果要关闭一个窗口&#xff0c;输入&#xff1a;exit即可&#xff1a;buffers 显示整个缓冲区列表ndG 删除从当前行到指定n行中的…