myJsonMarshal1.系统环境
操作系统:CentOS7
 硬件信息:使用virtual box配置虚拟机(内存3G、磁盘30G)
 编程语言:GO 1.15.2
2.项目的任务要求
func JsonMarshal(v interface{}) ([]byte, error)mytag:"你自己的定义"1.程序设计
reflectmyJsonMarshalmyJsonMarshal2.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())), nil
	case 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")
	}
}
reflect4.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
}
mytag:"你自己的定义"mytag:"name"6.MapTrans函数
//MapTrans 将map数据转为json字符流
func MapTrans(v interface{}) ([]byte, error) {
	json := reflect.ValueOf(v)
	i := json.MapRange()
	first := true
	b := "{"
	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 main
import (
	"fmt"
	"github.com/user/myJsonMarshal"
)
type Stu struct {
	Name  string `mytag:"name"`
	Age   int
	HIgh  bool
	Class *Class `mytag:"class"`
}
type Class struct {
	Name  string
	Grade int
}
func main() {
	//实例化一个数据结构,用于生成json字符串
	stu := Stu{
		Name: "张三",
		Age:  18,
		HIgh: true,
	}
	//指针变量
	cla := new(Class)
	cla.Name = "1班"
	cla.Grade = 3
	stu.Class = cla
	//Marshal失败时err!=nil
	jsonStu, err := myJsonMarshal.JsonMarshal(stu)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}
	//jsonStu是[]byte类型,转化成string类型便于查看
	fmt.Println(string(jsonStu))
}
mytag:"你自己的定义"3.单元测试
单元测试主要从程序员角度,对程序包的具体函数进行测试。
 建立myJsonMarshal_test.go文件,对程序包的每个函数进行单元测试如下,代码如下:
package myJsonMarshal
import (
	"fmt"
	"testing"
)
type Stu struct {
	Name  string `mytag:"name"`
	Age   int
	HIgh  bool
	Class *Class `mytag:"class"`
}
type Class struct {
	Name  string
	Grade int
}
func Test_JsonMarshal(t *testing.T) {
	//实例化一个数据结构,用于生成json字符串
	stu := Stu{
		Name: "张三",
		Age:  18,
		HIgh: true,
	}
	//指针变量
	cla := new(Class)
	cla.Name = "1班"
	cla.Grade = 3
	stu.Class = cla
	//Marshal失败时err!=nil
	jsonStu, 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 = 3
	stu.Class = cla
	//Marshal失败时err!=nil
	jsonStu, 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!=nil
	jsonStu, 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!=nil
	jsonStu, 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!=nil
	jsonStu, 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!=nil
	jsonStu, 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!=nil
	jsonStu, 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!=nil
	jsonStu, 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
首先安装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
 
