Directorio de artículos
Tareas del curso
-
Consulte la función Marshal del paquete oficial encoding / json para formatear los datos de estructura en un flujo de caracteres json
Debe exportar
func JsonMarshal(v interface{}) ([]byte, error)
Puede consultar o incluso copiar el código original
Admite etiquetas de campo (etiqueta), las etiquetas se encuentran
mytag:"你自己的定义"
No se permiten paquetes de terceros
-
El paquete debe incluir lo siguiente:
Documentación api china generada
Hay un buen archivo Léame, que incluye un caso de uso sencillo
Cada archivo go debe tener un archivo de prueba correspondiente
Descripción del diseño
Cree un nuevo paquete json , un nuevo archivo json.go , que implemente funciones func JsonMarshal(v interface{}) ([]byte, error)
.
En el estudio anterior, sabemos que en el idioma go, las iniciales en mayúscula indican que son accesibles en el exterior y las que no están en mayúscula son inaccesibles. En la implementación de la función JsonMarshal , inevitablemente necesitamos llamar a otras funciones para anidar muñecos , podemos encapsular otras funciones innecesarias, es decir, comenzar con una letra minúscula.
A través del código fuente oficial de codificación / JSON / encode.go , podemos conocer el proceso de aplicación general del Mariscal función, mediante el reflejo paquete, que también se llama en nuestras implementaciones posteriores.
La implementación en el documento oficial es relativamente complicada, porque se consideran muchos factores, y no consideramos tanto si implementamos una versión simplificada y utilizable .
La primera es la función func JsonMarshal(v interface{}) ([]byte, error)
.
func JsonMarshal(v interface{
}) ([]byte, error) {
b, err := marshal(v)
if err != nil {
return nil, err
}
return b, nil
}
Esto se logra llamando a una función privada marshal en el paquete .
Luego a la función func marshal(v interface{}) ([]byte, error)
.
func marshal(v interface{
}) ([]byte, error) {
if v == nil {
return []byte("null"), nil
}
s := reflect.ValueOf(v)
typeOfS := s.Type()
switch typeOfS.Kind() {
case reflect.Slice, reflect.Array :
return sliceMarshal(v)
case reflect.Struct :
return structMarshal(v)
case reflect.Map :
return mapMarshal(v)
case reflect.Ptr :
return marshal(s.Elem().Interface())
case reflect.String :
return []byte("\"" + s.String() + "\""), nil
default :
return []byte(fmt.Sprintf("%v", s.Interface())), nil
}
}
Primero, necesitamos determinar el tipo. Además de los tipos básicos como string e int, que se pueden devolver directamente, el tipo Ptr necesita tomar la dirección, y todo lo demás debe entregarse a la implementación de la función correspondiente.
Mira primero func sliceMarshal(v interface{}) ([]byte, error)
.
func sliceMarshal(v interface{
}) ([]byte, error) {
var b strings.Builder
b.WriteByte('[')
s := reflect.ValueOf(v)
for i := 0; i < s.Len(); i++ {
f := s.Index(i)
if i > 0 {
b.WriteByte(',')
}
tempB, e := marshal(f.Interface())
if e != nil {
return nil, e
}
b.Write(tempB)
}
b.WriteByte(']')
return []byte(b.String()), nil
}
Recorra la matriz / fragmento una vez y luego llame a la función marshal para volver a analizar el valor correspondiente . Matryoshka
Otra vezfunc structMarshal(v interface{}) ([]byte, error)
func structMarshal(v interface{
}) ([]byte, error) {
var b strings.Builder
b.WriteByte('{')
s := reflect.ValueOf(v)
typeOfS := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
if i > 0 {
b.WriteByte(',')
}
tag := typeOfS.Field(i).Tag.Get("mytag")
if tag == "" {
b.WriteString(fmt.Sprintf("\"%s\":", typeOfS.Field(i).Name))
} else {
b.WriteString(fmt.Sprintf("\"%s\":", tag))
}
tempB, e := marshal(f.Interface())
if e != nil {
return nil, e
}
b.Write(tempB)
}
b.WriteByte('}')
return []byte(b.String()), nil
}
El análisis del tipo de estructura es relativamente complicado, pero no es demasiado, solo necesita imprimir el nombre de la variable. Si hay una etiqueta, imprimirá la etiqueta correspondiente. El valor correspondiente también se analiza llamando de nuevo a la función marshal . Matryoshka
El último es func mapMarshal(v interface{}) ([]byte, error)
.
func mapMarshal(v interface{
}) ([]byte, error) {
var b strings.Builder
b.WriteByte('{')
s := reflect.ValueOf(v)
it := s.MapRange()
first := true
for it.Next() {
if first {
first = false
} else {
b.WriteByte(',')
}
b.WriteString(fmt.Sprintf("\"%v\":", it.Key()))
tempB, e := marshal(it.Value().Interface())
if e != nil {
return nil, e
}
b.Write(tempB)
}
b.WriteByte('}')
return []byte(b.String()), nil
}
Todavía queda atravesar el mapa nuevamente, imprimir la clave y el valor, y la muñeca
En este punto, la función func JsonMarshal(v interface{}) ([]byte, error)
está completa.
prueba
Escribir una prueba para cada función en json.go no parece ser de mucha utilidad, porque cada uno de ellos se llama muñecos.
type Monitor struct {
ID int
Name string
}
type Group struct {
ID int
Name string
Members []string
Nums [3]int
M Monitor `mytag:"GG"`
Manage map[int][]int
}
func ExampleSliceMarshal() {
b, err := sliceMarshal([]int{
1,2,3})
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(b))
//Output:[1,2,3]
}
func ExampleStructMarshal() {
group := Group{
ID:1,
Name:"Reds",
Members:[]string{
"Crimson", "Red", "Ruby", "Maroon"},
Nums:[3]int{
1,2,3},
M:Monitor{
18666,"yzdl"},
}
group.Manage= make(map[int][]int)
group.Manage[2] = []int{
1,2,3}
b, err := structMarshal(group)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(b))
//Output:{"ID":1,"Name":"Reds","Members":["Crimson","Red","Ruby","Maroon"],"Nums":[1,2,3],"GG":{"ID":18666,"Name":"yzdl"},"Manage":{"2":[1,2,3]}}
}
func ExampleMapMarshal() {
M := make(map[int][]int)
M[2] = []int{
1,2,3}
b, err := mapMarshal(M)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(b))
//Output:{"2":[1,2,3]}
}
func ExampleMarshal() {
b, err := marshal(123)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(b))
//Output:123
}
func ExampleJsonMarshal() {
group := Group{
ID:1,
Name:"Reds",
Members:[]string{
"Crimson", "Red", "Ruby", "Maroon"},
Nums:[3]int{
1,2,3},
M:Monitor{
18666,"yzdl"},
}
group.Manage= make(map[int][]int)
group.Manage[2] = []int{
1,2,3}
b, err := JsonMarshal(&group)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(b))
//Output:{"ID":1,"Name":"Reds","Members":["Crimson","Red","Ruby","Maroon"],"Nums":[1,2,3],"GG":{"ID":18666,"Name":"yzdl"},"Manage":{"2":[1,2,3]}}
}
Básicamente, cada tipo de valor lo ejecuta el mariscal.
Luego ejecute las instrucciones go build github.com/github-user/HHH/json
. Otros programas pueden import "github.com/github-user/HHH/json"
llamar a las funciones de este paquete.
Escribe test.go y pruébalo.
package main
import (
"fmt"
"github.com/github-user/HHH/json"
)
type Group struct {
ID int
Name string
}
type ColorGroup struct {
ID int
Name string
Colors []string
Nums [3]int
G Group `mytag:"GG"`
M map[int][]int
}
func main() {
group := ColorGroup{
ID:1,
Name:"Reds",
Colors:[]string{
"Crimson", "Red", "Ruby", "Maroon"},
Nums:[3]int{
1,2,3},
G:Group{
1,"123"},
}
group.M = make(map[int][]int)
group.M[2] = []int{
1,2,3}
b, err := json.JsonMarshal(group)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(b))
b, err = json.JsonMarshal(&group)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(b))
b, err = json.JsonMarshal("123456")
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(b))
}
La instrucción se ejecuta go run test.go
y el programa se ejecuta normalmente.
Generar documentación de API
Al igual que el trabajo anterior , la ejecución godoc
puede acceder a la API a través de la ruta correspondiente.