¿Cómo imprimir variables de estructura en la consola?

380

¿Cómo puedo imprimir (en la consola) el Id,Title , Name, etc de esta estructura en Golang?

type Project struct {
    Id      int64   `json:"project_id"`
    Title   string  `json:"title"`
    Name    string  `json:"name"`
    Data    Data    `json:"data"`
    Commits Commits `json:"commits"`
}
fnr
fuente
2
Todos ellos, para la depuración? Tratar fmt.Println.
Ry-

Respuestas:

641

Para imprimir el nombre de los campos en una estructura:

fmt.Printf("%+v\n", yourProject)

Del fmtpaquete :

al imprimir estructuras, el indicador más ( %+v) agrega nombres de campo

Eso supone que tiene una instancia de Proyecto (en ' yourProject')

El artículo JSON and Go dará más detalles sobre cómo recuperar los valores de una estructura JSON.


Esta página de ejemplo de Ir proporciona otra técnica:

type Response2 struct {
  Page   int      `json:"page"`
  Fruits []string `json:"fruits"`
}

res2D := &Response2{
    Page:   1,
    Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D)
fmt.Println(string(res2B))

Eso imprimiría:

{"page":1,"fruits":["apple","peach","pear"]}

Si no tiene ninguna instancia, debe usar la reflexión para mostrar el nombre del campo de una estructura dada, como en este ejemplo .

type T struct {
    A int
    B string
}

t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()

for i := 0; i < s.NumField(); i++ {
    f := s.Field(i)
    fmt.Printf("%d: %s %s = %v\n", i,
        typeOfT.Field(i).Name, f.Type(), f.Interface())
}
VonC
fuente
1
Gracias por su respuesta, pero hay una cosa más. Mis archivos JSON están relacionados con una API ... por lo tanto, no quiero establecer el Id o el Nombre, solo quiero obtenerlo a través de la API e imprimirlo en la consola. ¿Cómo puedo hacer eso?
fnr
44
@fnr Si tiene un documento JSON, deberá desarmarlo antes de poder imprimir su campo.
VonC 01 de
3
¡Votado! Mi única queja es que el comando% + v no lo imprime. Todavía estoy contento con la eficiencia de esta línea.
Shadoninja
1
Necesito importar "codificación / json" para la técnica de clasificación de json,
Jim Hoagland
1
Tenga en cuenta que .Printf ("% + v \ n") también funciona con el paquete "log"
Ariel Monaco
139

Quiero recomendar go-spew , que según su github "Implementa una impresora bastante profunda para estructuras de datos Go para ayudar en la depuración"

go get -u github.com/davecgh/go-spew/spew

ejemplo de uso:

package main

import (
    "github.com/davecgh/go-spew/spew"
)

type Project struct {
    Id      int64  `json:"project_id"`
    Title   string `json:"title"`
    Name    string `json:"name"`
    Data    string `json:"data"`
    Commits string `json:"commits"`
}

func main() {

    o := Project{Name: "hello", Title: "world"}
    spew.Dump(o)
}

salida:

(main.Project) {
 Id: (int64) 0,
 Title: (string) (len=5) "world",
 Name: (string) (len=5) "hello",
 Data: (string) "",
 Commits: (string) ""
}
Martin Olika
fuente
55
podría agregar la función de desreferencia que tiene go-spew. Le permite imprimir el valor de la estructura donde se hace referencia a un puntero y no al puntero mismo
El gran profesional con el uso de vomitar es que la salida ya está bien formateada, por lo que puede verificar fácilmente todas las propiedades del objeto.
Bobina
97

mis 2 centavos serían para usar json.MarshalIndent, me sorprende que esto no se sugiera, ya que es el más sencillo. por ejemplo:

func prettyPrint(i interface{}) string {
    s, _ := json.MarshalIndent(i, "", "\t")
    return string(s)
}

sin deps externos y resultados en una salida bien formateada.

mad.meesh
fuente
2
Opción interesante +1
VonC
1
Exactamente lo que estaba buscando. Impresión bonita y fácil con la reutilización de la biblioteca json integrada.
AdmiralThrawn
A menos que uno necesite imprimir el tipo y la longitud del campo (Spew es excelente para eso), esta solución es la mejor, ya que los punteros también se imprimen correctamente.
Christophe Vidal
👏🏻 Corto y dulce. Puede reemplazar "\t"con " "si quiere sangría espacial en su lugar
Dana Woodman
1
Es de destacar que Marshal()solo serializa los campos exportados de una estructura; sin embargo, es perfecto para los mapas.
nobar
24

Creo que sería mejor implementar un stringer personalizado si desea algún tipo de salida formateada de un struct

por ejemplo

package main

    import "fmt"

    type Project struct {
        Id int64 `json:"project_id"`
        Title string `json:"title"`
        Name string `json:"name"`
    }

    func (p Project) String() string {
        return fmt.Sprintf("{Id:%d, Title:%s, Name:%s}", p.Id, p.Title, p.Name)
    }

    func main() {
        o := Project{Id: 4, Name: "hello", Title: "world"}
        fmt.Printf("%+v\n", o)
    }
Vivek Maru
fuente
18
p = Project{...}
fmt.Printf("%+v", p)
fmt.Printf("%#v", p) //with type
Coca Cola
fuente
2
fmt.Printf(%#v, p), me arroja main.structcon struct type cuál es la diferencia entre "%#v"y "%+v"@cokebol
muthukumar helius
13

Alternativamente, intente usar esta función PrettyPrint()

// print the contents of the obj
func PrettyPrint(data interface{}) {
    var p []byte
    //    var err := error
    p, err := json.MarshalIndent(data, "", "\t")
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("%s \n", p)
}

Para usar esto, no necesita ningún paquete adicional con la excepción de , fmty encoding/jsonsolo una referencia, puntero o literal de la estructura que ha creado.

Para usar solo tome su estructura, inicialícela en main o en cualquier paquete en el que se encuentre y páselo PrettyPrint().

type Prefix struct {
    Network string
    Mask    int
}

func valueStruct() {
    // struct as a value
    var nw Prefix
    nw.Network = "10.1.1.0"
    nw.Mask = 24
    fmt.Println("### struct as a pointer ###")
    PrettyPrint(&nw)
}

Su salida sería

### struct as a pointer ###
{
    "Network": "10.1.1.0",
    "Mask": 24
} 

Juega un poco con el código aquí .

Erik Toor
fuente
5

Me gusta la basura .

De su léame:

type Person struct {
  Name   string
  Age    int
  Parent *Person
}

litter.Dump(Person{
  Name:   "Bob",
  Age:    20,
  Parent: &Person{
    Name: "Jane",
    Age:  50,
  },
})

Sdump es bastante útil en las pruebas:

func TestSearch(t *testing.T) {
  result := DoSearch()

  actual := litterOpts.Sdump(result)
  expected, err := ioutil.ReadFile("testdata.txt")
  if err != nil {
    // First run, write test data since it doesn't exist
        if !os.IsNotExist(err) {
      t.Error(err)
    }
    ioutil.Write("testdata.txt", actual, 0644)
    actual = expected
  }
  if expected != actual {
    t.Errorf("Expected %s, got %s", expected, actual)
  }
}
qed
fuente
5

Recomiendo usar Pretty Printer Library . En eso puedes imprimir cualquier estructura muy fácilmente.

  1. Instalar biblioteca

    https://github.com/kr/pretty

o

go get github.com/kr/pretty

Ahora haz esto en tu código

package main

import (
fmt
github.com/kr/pretty
)

func main(){

type Project struct {
    Id int64 `json:"project_id"`
    Title string `json:"title"`
    Name string `json:"name"`
    Data Data `json:"data"`
    Commits Commits `json:"commits"`
}

fmt.Printf("%# v", pretty.Formatter(Project)) //It will print all struct details

fmt.Printf("%# v", pretty.Formatter(Project.Id)) //It will print component one by one.

}

También puede obtener la diferencia entre el componente a través de esta biblioteca y mucho más. También puede consultar la biblioteca de documentos aquí.

amku91
fuente
1
Sería útil ver el ejemplo de la salida generada porpretty.Formatter
Konstantin Tikhonov
4

Cuando tenga estructuras más complejas, es posible que necesite convertir a JSON antes de imprimir:

// Convert structs to JSON.
data, err := json.Marshal(myComplexStruct)
fmt.Printf("%s\n", data)

Fuente: https://gist.github.com/tetsuok/4942960

Cassio
fuente
3

Visita aquí para ver el código completo. Aquí también encontrará un enlace para un terminal en línea donde se puede ejecutar el código completo y el programa representa cómo extraer la información de la estructura (nombre del campo, su tipo y valor). A continuación se muestra el fragmento de programa que solo imprime los nombres de campo.

package main

import "fmt"
import "reflect"

func main() {
    type Book struct {
        Id    int
        Name  string
        Title string
    }

    book := Book{1, "Let us C", "Enjoy programming with practice"}
    e := reflect.ValueOf(&book).Elem()

    for i := 0; i < e.NumField(); i++ {
        fieldName := e.Type().Field(i).Name
        fmt.Printf("%v\n", fieldName)
    }
}

/*
Id
Name
Title
*/
Hullull
fuente
2

También hay go-render , que maneja la recursividad del puntero y mucha clasificación de claves para cadenas y mapas int.

Instalación:

go get github.com/luci/go-render/render

Ejemplo:

type customType int
type testStruct struct {
        S string
        V *map[string]int
        I interface{}
}

a := testStruct{
        S: "hello",
        V: &map[string]int{"foo": 0, "bar": 1},
        I: customType(42),
}

fmt.Println("Render test:")
fmt.Printf("fmt.Printf:    %#v\n", a)))
fmt.Printf("render.Render: %s\n", Render(a))

Que imprime:

fmt.Printf:    render.testStruct{S:"hello", V:(*map[string]int)(0x600dd065), I:42}
render.Render: render.testStruct{S:"hello", V:(*map[string]int){"bar":1, "foo":0}, I:render.customType(42)}
mdwhatcott
fuente
1
fmt.Printf("%+v\n", project)

Esta es la forma básica de imprimir los detalles.

0ejemplo.com
fuente
0

Otra forma es crear un func llamado toStringque tome struct, formatear los campos como desee.

import (
    "fmt"
)

type T struct {
    x, y string
}

func (r T) toString() string {
    return "Formate as u need :" + r.x + r.y
}

func main() {
    r1 := T{"csa", "ac"}
    fmt.Println("toStringed : ", r1.toString())
}
pschilakanti
fuente
2
O podría implementar la Stringerinterfaz. Se vería así: func (t T) String() string { return fmt.Sprintf("SomeT{TID: %d, TField: %d, SomeTField: %s, SomeAnotherField: %s}", t.ID, t.Field, t.SomeTField, t.SomeAnotherField) }
rbo13
0

Sin usar bibliotecas externas y con una nueva línea después de cada campo:

log.Println(
            strings.Replace(
                fmt.Sprintf("%#v", post), ", ", "\n", -1))
Vladimir Babin
fuente
0
    type Response struct {
        UserId int    `json:"userId"`
        Id     int    `json:"id"`
        Title  string `json:"title"`
        Body   string `json:"body"`
    }

    func PostsGet() gin.HandlerFunc {
        return func(c *gin.Context) {
            xs, err := http.Get("https://jsonplaceholder.typicode.com/posts")
            if err != nil {
                log.Println("The HTTP request failed with error: ", err)
            }
            data, _ := ioutil.ReadAll(xs`enter code here`.Body)


            // this will print the struct in console            
            fmt.Println(string(data))


            // this is to send as response for the API
            bytes := []byte(string(data))
            var res []Response
            json.Unmarshal(bytes, &res)

            c.JSON(http.StatusOK, res)
        }
    }
Aditya Singh Manhas
fuente
0

muy simple no tengo la estructura de datos y confirmaciones, así que cambié el

package main

import (
    "fmt"
)

type Project struct {
    Id      int64   `json:"project_id"`
    Title   string  `json:"title"`
    Name    string  `json:"name"`
    Data    string  `json:"data"`
    Commits string  `json:"commits"`
}

func main() {
    p := Project{
    1,
    "First",
    "Ankit",
    "your data",
    "Commit message",
    }
    fmt.Println(p)
}

Para aprender, puede obtener ayuda desde aquí: https://gobyexample.com/structs

Ankit Malik
fuente
0

Tal vez esto no debería aplicarse a las solicitudes de producción, pero si está en modo de depuración, le sugiero que siga el siguiente enfoque.

marshalledText, _ := json.MarshalIndent(inputStruct, "", " ")
fmt.Println(string(marshalledText))

Esto da como resultado el formateo de los datos en formato json con mayor legibilidad.

mourya venkat
fuente
-7
fmt.Println("%+v", structure variable)

Una mejor manera de hacer esto sería crear una constante global para la cadena "% + v" en un paquete llamado "commons" (quizás) y usarla en todas partes en su código

//In commons package
const STRUCTURE_DATA_FMT = "%+v"

//In your code everywhere
fmt.Println(commons.STRUCTURE_DATA_FMT, structure variable)
Jithendra Kumar
fuente
3
Cortésmente, la gente ha rechazado esto porque la Printlnfunción no acepta un argumento de cadena de formato. Dices que una constante global es mejor pero no has justificado por qué es mejor que la respuesta marcada. Ha creado una etiqueta no estándar para una cadena de formato conocida. La etiqueta es mucho más larga, más difícil de recordar y nadie más que trabaje en su código la usaría. Utiliza ALL_CAPS y un guión bajo del cual todos los Golang Linter se quejarán. La convención es mixedCaps golang.org/doc/effective_go.html#mixed-caps Probablemente sea mejor eliminar esta respuesta.
Davos