Come stampare le variabili struct nella console?


380

Come posso stampare (nella console) il Id, Title, Name, ecc di questa struct in 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"`
}

2
Tutti loro, per il debug? Prova fmt.Println.
Ry-

Risposte:


641

Per stampare il nome dei campi in una struttura:

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

Dal fmtpacchetto :

quando si stampano le strutture, il flag più ( %+v) aggiunge i nomi dei campi

Ciò suppone che tu abbia un'istanza di Project (in ' yourProject')

L'articolo JSON e Go forniranno maggiori dettagli su come recuperare i valori da una struttura JSON.


Questa pagina Vai all'esempio fornisce un'altra tecnica:

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

Che stamperebbe:

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

Se non si dispone di alcuna istanza, è necessario utilizzare reflection per visualizzare il nome del campo di una determinata struttura, come in questo esempio .

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

1
Grazie per la risposta, ma c'è un'altra cosa. I miei file JSON sono correlati a un'API ... per cui non voglio impostare l'ID o il nome, voglio solo ottenerlo sull'API e stamparlo nella console. Come lo posso fare?
fnr

4
@fnr Se si dispone di un documento JSON, è necessario decomprimerlo prima di poter stampare il suo campo.
VonC

3
Upvoted! La mia unica lamentela è che il comando% + v non lo stampa abbastanza! Sono ancora contento dell'efficienza di questa linea.
Shadoninja,

1
È necessario eseguire l'importazione di "codifica / json" per la tecnica di smistamento json,
Jim Hoagland,

1
Si noti che .Printf ("% + v \ n") funziona anche con il pacchetto "log"
Ariel Monaco,

139

Voglio raccomandare go-spew , che secondo il loro github "Implementa una stampante piuttosto profonda per le strutture dati Go per facilitare il debug"

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

esempio di utilizzo:

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

produzione:

(main.Project) {
 Id: (int64) 0,
 Title: (string) (len=5) "world",
 Name: (string) (len=5) "hello",
 Data: (string) "",
 Commits: (string) ""
}

5
potresti aggiungere la caratteristica di dereference che go-spew ha. Ti consente di stampare il valore della struttura a cui fa riferimento un puntatore e non il relativo puntatore

Il grande professionista con use spew è che l'output è già ben formattato in modo da poter controllare facilmente tutte le proprietà dell'oggetto.
Bobina

97

i miei 2 centesimi sarebbero da usare json.MarshalIndent- sorpreso che questo non sia suggerito, in quanto è il più semplice. per esempio:

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

nessun deps esterno e produce un output ben formattato.


2
Opzione interessante. +1
VonC,

1
Esattamente quello che stavo cercando. Stampa semplice e carina con il riutilizzo della libreria json integrata.
AmmiraglioTrawn

A meno che non sia necessario stampare il tipo e la lunghezza del campo (Spew è ottimo per questo), questa soluzione è la migliore in quanto anche i puntatori sono stampati correttamente!
Christophe Vidal,

👏🏻 Breve e dolce. Puoi sostituirlo "\t"con " "se vuoi invece rientrare nello spazio
Dana Woodman,

1
Da notare, Marshal()serializza solo i campi esportati di una struttura, ma è perfetto per le mappe.
nobar

24

Penso che sarebbe meglio implementare uno stringer personalizzato se si desidera un tipo di output formattato di a struct

per esempio

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

18
p = Project{...}
fmt.Printf("%+v", p)
fmt.Printf("%#v", p) //with type

2
fmt.Printf(%#v, p), mi lancia main.structcon struct type qual è la differenza tra "%#v"e "%+v"@cokebol
muthukumar helius

13

In alternativa, prova a utilizzare questa funzione 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)
}

Per usarlo non hai bisogno di pacchetti aggiuntivi ad eccezione di , fmte encoding/jsonsolo un riferimento, un puntatore o letterale della struttura che hai creato.

Per usare basta prendere la tua struttura, inizializzarla nel pacchetto principale o in qualunque altro pacchetto e passarla 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)
}

Il suo output sarebbe

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

Gioca con il codice qui .


5

Mi piacciono i rifiuti .

Dal loro readme:

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

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

Sdump è abbastanza utile nei test:

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

5

Consiglio di usare Pretty Printer Library . In questo puoi stampare qualsiasi struttura molto facilmente.

  1. Installa libreria

    https://github.com/kr/pretty

o

go get github.com/kr/pretty

Ora fai così nel tuo codice

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.

}

Inoltre puoi ottenere la differenza tra i componenti attraverso questa libreria e molto altro. Puoi anche dare un'occhiata alla libreria Documenti qui.


1
Sarebbe utile vedere l'esempio dell'output generato dapretty.Formatter
Konstantin Tikhonov il

4

Quando si hanno strutture più complesse, potrebbe essere necessario convertire in JSON prima di stampare:

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

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


3

Visita qui per vedere il codice completo. Qui troverai anche un collegamento per un terminale online in cui è possibile eseguire il codice completo e il programma rappresenta come estrarre le informazioni sulla struttura (nome del campo, tipo e valore). Di seguito è riportato il frammento di programma che stampa solo i nomi dei campi.

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
*/

2

C'è anche go-render , che gestisce la ricorsione del puntatore e un sacco di ordinamento delle chiavi per le stringhe e le mappe int.

Installazione:

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

Esempio:

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

Che stampa:

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

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

Questo è il modo di base per stampare i dettagli


0

Un altro modo è, creare una funzione chiamata toStringche richiede struct, formattare i campi come si desidera.

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

2
Oppure potresti implementare l' Stringerinterfaccia. Sarebbe simile a questo: 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

Senza utilizzare librerie esterne e con una nuova riga dopo ogni campo:

log.Println(
            strings.Replace(
                fmt.Sprintf("%#v", post), ", ", "\n", -1))

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

0

molto semplice Non ho la struttura di dati e commit Quindi ho cambiato il

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

Per l'apprendimento puoi chiedere aiuto da qui: https://gobyexample.com/structs


0

Forse questo non dovrebbe essere applicato per le richieste di produzione ma se sei in modalità debug ti suggerisco di seguire l'approccio seguente.

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

Ciò comporta la formattazione dei dati in formato json con una maggiore leggibilità.



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

Un modo migliore per farlo sarebbe quello di creare una costante globale per la stringa "% + v" in un pacchetto chiamato "commons" (forse) e usarla ovunque nel tuo codice

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

//In your code everywhere
fmt.Println(commons.STRUCTURE_DATA_FMT, structure variable)

3
Gentilmente, le persone hanno votato in negativo questo perché la Printlnfunzione non accetta un argomento di stringa di formato. Dici che una costante globale è migliore ma non hai giustificato il motivo per cui è migliore della risposta contrassegnata. Hai creato un'etichetta non standard per una stringa di formato ben nota. L'etichetta è molto più lunga, più difficile da ricordare e nessun altro che lavora sul tuo codice lo userebbe. Utilizza sia ALL_CAPS sia un carattere di sottolineatura di cui ogni linter golang si lamenterà. La convenzione è mixedCaps golang.org/doc/effective_go.html#mixed-caps Probabilmente è meglio rimuovere questa risposta.
Davos,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.