example convertir bytes binascii binario python json dictionary go

convertir - bytes() python



Tomar una cadena JSON, desarmarla en una interfaz de mapa[cadena]{}, editarla y ordenarla en un byte[] parece más complicado de lo que debería ser (2)

No, esta no es la forma más correcta de manejar datos JSON estructurados en Go. En cambio, es mejor crear una "jerarquía de estructura" y desarmar su JSON en estructuras. P.ej

type Data struct { Key1 string Key2 struct { C1Key1 string } Key3 []Key3 } type Key3 struct { C2Key1 struct { C3Key1 string } }

Este enfoque:

  • le da más control sobre cómo sus datos serán ( json.Marshaler ) json.Marshaler (a través de etiquetas de estructura e interfaces json.Unmarshaler y json.Marshaler )
  • te deshace de las aserciones tipo
  • en cambio, le da más seguridad de tipo
  • tiene un mejor rendimiento, ya que el acceso a la estructura es básicamente gratuito en comparación con el acceso al mapa.

Área de juegos: https://play.golang.org/p/9XIh8DX1Ms .

Estoy haciendo una manipulación JSON muy básica para aprender un poco de Go, y funciona, excepto que una cosa parece incorrecta, tengo que escribir una gran cantidad de .(map[string]interface{}) y .([]interface{}) para acceder entradas en el JSON, especialmente si son hijos de hijos de niños, etc.

Ver aquí (también en Go Playground: https://play.golang.org/p/Wd-pzHqTsU ):

package main import ( "fmt" "encoding/json" ) func main() { JSON := []byte(`{"key1":"val1","key2":{"c1key1":"c1val1"},"key3":[{"c2key1":{"c3key1":"c3val1"}}]}`) fmt.Printf("%s/n", JSON) var d map[string]interface{} json.Unmarshal(JSON, &d) fmt.Println(d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"]) d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"] = "change1" fmt.Println(d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"]) JSON, _ = json.Marshal(d) fmt.Printf("%s/n", JSON) }

Que devuelve:

{"key1":"val1","key2":{"c1key1":"c1val1"},"key3":[{"c2key1":{"c3key1":"c3val1"}}]} c3val1 change1 {"key1":"val1","key2":{"c1key1":"c1val1"},"key3":[{"c2key1":{"c3key1":"change1"}}]}

Ahora, en Python, solo accedo a la clave / valores directamente en lugar de definir el tipo de lo que estoy accediendo cada vez, es decir, en lugar de fmt.Println(d["key3"].([]interface{})[0].(map[string]interface{})["c2key1"].(map[string]interface{})["c3key1"]) print d["key3"][0]["c2key1"]["c3key1"]

Ejemplo de Python:

import json JSON = ''{"key3": [{"c2key1": {"c3key1": "c3val1"}}], "key2": {"c1key1": "c1val1"}, "key1": "val1"}'' print JSON d = json.loads(JSON) print d["key3"][0]["c2key1"]["c3key1"] d["key3"][0]["c2key1"]["c3key1"] = "change1" print d["key3"][0]["c2key1"]["c3key1"] JSON = json.dumps(d) print JSON

Entonces, ¿estoy haciendo esto bien en Go? Y si es así, ¿cuál es la razón de este diseño? O si no, ¿cómo debo hacerlo?


Prefacio: Optimicé y mejoré la solución a continuación, y la github.com/icza/dyno como una biblioteca aquí: github.com/icza/dyno .

La forma más limpia sería crear tipos predefinidos (estructuras de struct ) que modelen su JSON, y desarmar a un valor de ese tipo, y simplemente puede referirse a elementos usando Selectors (para tipos de struct ) y expresiones de Índice (para mapas y sectores) .

Sin embargo, si su entrada no es de una estructura predefinida, le sugiero las siguientes 2 funciones auxiliares: get() y set() . El primero accede (devuelve) un elemento arbitrario especificado por una ruta arbitraria (lista de claves del mapa de string y / o índices de corte int ), el segundo cambia (establece) el valor especificado por una ruta arbitraria (las implementaciones de estas funciones auxiliares están en El final de la respuesta).

Solo tiene que incluir estas 2 funciones una vez en su proyecto / aplicación.

Y ahora, utilizando estos ayudantes, las tareas que desea realizar se vuelven simples (al igual que la solución de Python):

fmt.Println(get(d, "key3", 0, "c2key1", "c3key1")) set("NEWVALUE", d, "key3", 0, "c2key1", "c3key1") fmt.Println(get(d, "key3", 0, "c2key1", "c3key1"))

Salida:

change1 NEWVALUE

Prueba tu aplicación modificada en Go Playground .

Nota - Simplificación adicional:

Incluso puede guardar la ruta en una variable y reutilizarla para simplificar aún más el código anterior:

path := []interface{}{"key3", 0, "c2key1", "c3key1"} fmt.Println(get(d, path...)) set("NEWVALUE", d, path...) fmt.Println(get(d, path...))

Y las implementaciones de get() y set() están a continuación. Nota: comprueba si la ruta es válida se omite. Esta implementación utiliza interruptores de tipo :

func get(m interface{}, path ...interface{}) interface{} { for _, p := range path { switch idx := p.(type) { case string: m = m.(map[string]interface{})[idx] case int: m = m.([]interface{})[idx] } } return m } func set(v interface{}, m interface{}, path ...interface{}) { for i, p := range path { last := i == len(path)-1 switch idx := p.(type) { case string: if last { m.(map[string]interface{})[idx] = v } else { m = m.(map[string]interface{})[idx] } case int: if last { m.([]interface{})[idx] = v } else { m = m.([]interface{})[idx] } } } }