Como imprimir variáveis ​​de estrutura no console?

380

Como posso imprimir (no console) a Id, Title, Name, etc. deste struct em 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
fonte
2
Todos eles, para depuração? Tente fmt.Println.
Ry-

Respostas:

641

Para imprimir o nome dos campos em uma estrutura:

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

Do fmtpacote :

ao imprimir estruturas, o sinalizador de adição ( %+v) adiciona nomes de campos

Isso supõe que você tenha uma instância do Project (em ' yourProject')

O artigo JSON e Go fornecerá mais detalhes sobre como recuperar os valores de uma estrutura JSON.


Esta página Ir por exemplo fornece outra 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))

Isso imprimiria:

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

Se você não tiver nenhuma instância, precisará usar reflexão para exibir o nome do campo de uma determinada estrutura, como neste exemplo .

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
fonte
11
Obrigado pela sua resposta, mas há mais uma coisa. Meus arquivos JSON estão relacionados a uma API ... portanto, não quero definir o ID ou o Nome, apenas quero obtê-lo pela API e imprimi-lo no console. Como eu posso fazer isso?
FNR
4
@fnr Se você possui um documento JSON, precisará retirá-lo da ordem antes de poder imprimir seu campo.
VonC
3
Voto a favor! Minha única reclamação é que o comando% + v não o imprime! Ainda estou feliz com a eficiência dessa linha.
Shadoninja
11
Necessidade de fazer importação "de codificação / json" para a técnica json triagem,
Jim Hoagland
11
Observe que .Printf ("% + v \ n") também funciona com o pacote "log"
Ariel Monaco
139

Quero recomendar go-spew , que de acordo com o github "Implementa uma impressora bonita e profunda para estruturas de dados Go para ajudar na depuração"

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

exemplo 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)
}

resultado:

(main.Project) {
 Id: (int64) 0,
 Title: (string) (len=5) "world",
 Name: (string) (len=5) "hello",
 Data: (string) "",
 Commits: (string) ""
}
Martin Olika
fonte
5
você pode adicionar o recurso de desreferência que o go-spew possui. Ele permite que você imprima o valor da estrutura em que um ponteiro está fazendo referência e não o ponteiro em si
O grande profissional com o uso de spew é que a saída já está bem formatada para que você possa verificar facilmente todas as propriedades do objeto.
bobina
97

meus 2 centavos seriam usados json.MarshalIndent- surpreso que isso não seja sugerido, pois é o mais direto. por exemplo:

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

nenhum departamento externo e resulta em uma saída bem formatada.

mad.meesh
fonte
2
Opção interessante. +1
VonC
11
Exatamente o que eu estava procurando. Impressão bonita fácil com reutilização da biblioteca json incorporada.
AdmiralThrawn
A menos que seja necessário imprimir o tipo e o comprimento do campo (o Spew é ótimo para isso), esta solução é a melhor, pois os ponteiros também são impressos corretamente!
Christophe Vidal
Short🏻 Curto e doce. Você pode substituir "\t"com " "se você quiser recuo espaço em vez
Dana Woodman
11
De notar, Marshal()apenas serializa os campos exportados de uma estrutura - é perfeito para mapas.
Nobar
24

Eu acho que seria melhor implementar uma longarina personalizada se você quiser algum tipo de saída formatada de um struct

por exemplo

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
fonte
18
p = Project{...}
fmt.Printf("%+v", p)
fmt.Printf("%#v", p) //with type
cokeboL
fonte
2
fmt.Printf(%#v, p), Atira-me main.structcom struct type o que é a diferença entre "%#v"e "%+v"@cokebol
Helius Muthukumar
13

Como alternativa, tente usar esta função 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 isso, você não precisa de pacotes adicionais, com exceção de fmte encoding/jsonapenas uma referência, ponteiro ou literal da estrutura que você criou.

Para usar apenas pegue sua estrutura, inicialize-a no pacote principal ou em qualquer que seja o pacote e passe-o para 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)
}

Sua saída seria

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

Brinque com o código aqui .

Erik Toor
fonte
5

Eu gosto de lixo .

De seu leia-me:

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

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

Sdump é bastante útil em testes:

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
fonte
5

Eu recomendo usar a Pretty Printer Library . Em que você pode imprimir qualquer estrutura com muita facilidade.

  1. Instalar Biblioteca

    https://github.com/kr/pretty

ou

go get github.com/kr/pretty

Agora faça isso no seu 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.

}

Além disso, você pode obter diferença entre os componentes desta biblioteca e muito mais. Você também pode dar uma olhada na biblioteca do Documentos aqui.

amku91
fonte
11
Seria útil ver o exemplo da saída gerada porpretty.Formatter
Konstantin Tikhonov
4

Quando você possui estruturas mais complexas, pode ser necessário converter para JSON antes de imprimir:

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

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

Cássio
fonte
3

Visite aqui para ver o código completo. Aqui você também encontrará um link para um terminal on-line onde o código completo pode ser executado e o programa representa como extrair as informações da estrutura (nome do campo, tipo e valor). Abaixo está o trecho de programa que imprime apenas os nomes dos campos.

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
*/
hygull
fonte
2

Há também go-render , que lida com a recursão do ponteiro e muita classificação de chave para os mapas string e int.

Instalação:

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

Exemplo:

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
fonte
1
fmt.Printf("%+v\n", project)

Esta é a maneira básica de imprimir os detalhes

0example.com
fonte
0

Outra maneira é criar uma função chamada toStringque aceite struct, formate os campos como desejar.

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
fonte
2
Ou você pode implementar a Stringerinterface. Seria algo como isto: 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 01/01
0

Sem usar bibliotecas externas e com nova linha após cada campo:

log.Println(
            strings.Replace(
                fmt.Sprintf("%#v", post), ", ", "\n", -1))
Vladimir Babin
fonte
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
fonte
0

muito simples eu não tenho a estrutura de dados e confirma então mudei o

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, você pode obter ajuda aqui: https://gobyexample.com/structs

Ankit Malik
fonte
0

Talvez isso não deva ser aplicado para solicitações de produção, mas se você estiver no modo de depuração, sugiro que você siga a abordagem abaixo.

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

Isso resulta na formatação dos dados no formato json com maior legibilidade.

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

Uma maneira melhor de fazer isso seria criar uma constante global para a string "% + v" em um pacote chamado "commons" (talvez) e usá-la em qualquer lugar do código

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

//In your code everywhere
fmt.Println(commons.STRUCTURE_DATA_FMT, structure variable)
Jithendra Kumar
fonte
3
Educadamente, as pessoas votaram negativamente nisso porque a Printlnfunção não aceita um argumento de cadeia de formato. Você diz que uma constante global é melhor, mas não justificou por que é melhor que a resposta marcada. Você criou um rótulo não padrão para uma sequência de formato conhecida. O rótulo é muito mais longo, mais difícil de lembrar e ninguém mais que trabalha no seu código o usaria. Ele usa ALL_CAPS e um sublinhado sobre o qual todos os golang-langs se queixam. A convenção é mixedCaps golang.org/doc/effective_go.html#mixed-caps Provavelmente, é melhor remover esta resposta.
Davos