Informática de servicios (5) -Desarrollo de un paquete de soporte de serialización de objetos

Tareas del curso

  1. 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

  2. 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.

Inserte la descripción de la imagen aquí

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.goy el programa se ejecuta normalmente.

Inserte la descripción de la imagen aquí

Generar documentación de API

Al igual que el trabajo anterior , la ejecución godocpuede acceder a la API a través de la ruta correspondiente.

Inserte la descripción de la imagen aquí

Entrega de Trabajo

Mi código completo

Supongo que te gusta

Origin blog.csdn.net/qq_43278234/article/details/109278731
Recomendado
Clasificación