Comment imprimer des variables de structure dans la console?

381

Comment puis - je imprimer (dans la console) le Id, Title, Name, etc. de cette struct dans 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
la source
2
Tous, pour le débogage? Essayez fmt.Println.
Ry-

Réponses:

641

Pour imprimer le nom des champs dans une structure:

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

De l' fmtemballage :

lors de l'impression de structures, l'indicateur plus ( %+v) ajoute des noms de champ

Cela suppose que vous ayez une instance de Project (dans ' yourProject')

L'article JSON et Go donnera plus de détails sur la façon de récupérer les valeurs d'une structure JSON.


Cette page d'exemple Go fournit une autre technique:

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

Cela imprimerait:

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

Si vous n'avez aucune instance, vous devez utiliser la réflexion pour afficher le nom du champ d'une structure donnée, comme dans cet exemple .

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
la source
1
Merci pour votre réponse mais il y a encore une chose. Mes fichiers JSON sont liés à une API ... pour cette raison, je ne veux pas définir l'ID ou le nom, je veux simplement le récupérer sur l'API et l'imprimer dans la console. Comment puis je faire ça?
fnr
4
@fnr Si vous avez un document JSON, vous devrez le démonter avant de pouvoir imprimer son champ.
VonC
3
A voté! Ma seule plainte est que la commande% + v ne l'imprime pas assez! Je suis toujours satisfait de l'efficacité de cette ligne.
Shadoninja
1
Besoin d'importer "encoding / json" pour la technique de marshalling json,
Jim Hoagland
1
Notez que .Printf ("% + v \ n") fonctionne également avec le package "log"
Ariel Monaco
140

Je veux recommander go-spew , qui selon leur github "implémente une jolie imprimante profonde pour les structures de données Go pour aider au débogage"

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

exemple d'utilisation:

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

production:

(main.Project) {
 Id: (int64) 0,
 Title: (string) (len=5) "world",
 Name: (string) (len=5) "hello",
 Data: (string) "",
 Commits: (string) ""
}
Martin Olika
la source
5
vous pouvez ajouter la fonction de déréférencement de go-spew. Il vous permet d'imprimer la valeur de la structure où un pointeur fait référence et non le pointeur itsel
Le gros pro avec l'utilisation de spew est que la sortie est déjà bien formatée afin que vous puissiez facilement vérifier toutes les propriétés de l'objet.
COil
97

mes 2 cents seraient à utiliser json.MarshalIndent- surpris, ce n'est pas suggéré, car c'est le plus simple. par exemple:

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

pas de dépôts externes et donne une sortie bien formatée.

mad.meesh
la source
2
Option intéressante. +1
VonC
1
Exactement ce que je cherchais. Jolie impression facile avec réutilisation de la bibliothèque json intégrée.
AdmiralThrawn
À moins qu'il ne soit nécessaire d'imprimer le type et la longueur du champ (Spew est idéal pour cela), cette solution est juste la meilleure car les pointeurs sont également correctement imprimés!
Christophe Vidal
👏🏻 Court et doux. Vous pouvez remplacer "\t"par " "si vous voulez mettre en retrait l'espace à la place
Dana Woodman
1
À noter, Marshal()ne sérialise que les champs exportés d'une structure - c'est parfait pour les cartes.
nobar
24

Je pense qu'il serait préférable d'implémenter un limon personnalisé si vous voulez une sorte de sortie formatée d'un struct

par exemple

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
la source
18
p = Project{...}
fmt.Printf("%+v", p)
fmt.Printf("%#v", p) //with type
cokeboL
la source
2
fmt.Printf(%#v, p), me lance main.structavec struct type quelle est la différence entre "%#v"et "%+v"@cokebol
muthukumar helius
13

Alternativement, essayez d'utiliser cette fonction 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)
}

Pour l'utiliser, vous n'avez pas besoin de packages supplémentaires à l'exception de fmtet encoding/json, juste une référence, un pointeur vers ou un littéral de la structure que vous avez créée.

Pour utiliser, prenez simplement votre structure, initialisez-la dans le paquet principal ou dans le paquet dans lequel vous vous trouvez et passez-la 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)
}

Sa sortie serait

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

Jouez avec le code ici .

Erik Toor
la source
5

J'aime la litière .

De leur readme:

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

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

Sdump est assez pratique dans les tests:

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
la source
5

Je recommande d'utiliser Pretty Printer Library . En cela, vous pouvez imprimer n'importe quelle structure très facilement.

  1. Installer la bibliothèque

    https://github.com/kr/pretty

ou

go get github.com/kr/pretty

Maintenant, fais comme ça dans ton code

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.

}

Vous pouvez également obtenir la différence entre les composants via cette bibliothèque et bien plus encore. Vous pouvez également consulter les documents de la bibliothèque ici.

amku91
la source
1
Serait utile de voir l'exemple de la sortie générée parpretty.Formatter
Konstantin Tikhonov
4

Lorsque vous avez des structures plus complexes, vous devrez peut-être convertir en JSON avant d'imprimer:

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

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

Cassio
la source
3

Visitez ici pour voir le code complet. Ici, vous trouverez également un lien vers un terminal en ligne où le code complet peut être exécuté et le programme représente comment extraire les informations de la structure (nom du champ leur type et valeur). Ci-dessous, l'extrait de programme qui imprime uniquement les noms de champ.

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
la source
2

Il y a aussi go-render , qui gère la récursivité du pointeur et beaucoup de tri de clé pour les cartes de chaîne et int.

Installation:

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

Exemple:

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

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

Il s'agit de la méthode de base pour imprimer les détails

0example.com
la source
0

Une autre façon est de créer un func appelé toStringqui prend struct, formatez les champs comme vous le souhaitez.

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
la source
2
Ou vous pouvez implémenter l' Stringerinterface. Cela ressemblerait à ceci: 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

Sans utiliser de bibliothèques externes et avec une nouvelle ligne après chaque champ:

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

très simple, je n'ai pas la structure des données et des validations J'ai donc changé la

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

Pour apprendre, vous pouvez obtenir de l'aide à partir d'ici: https://gobyexample.com/structs

Ankit Malik
la source
0

Peut-être que cela ne devrait pas être appliqué pour les demandes de production, mais si vous êtes en mode débogage, je vous suggère de suivre l'approche ci-dessous.

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

Il en résulte un formatage des données au format json avec une lisibilité accrue.

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

Une meilleure façon de procéder serait de créer une constante globale pour la chaîne "% + v" dans un package appelé "commons" (peut-être) et de l'utiliser partout dans votre code

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

//In your code everywhere
fmt.Println(commons.STRUCTURE_DATA_FMT, structure variable)
Jithendra Kumar
la source
3
Poliment, les gens ont voté contre parce que la Printlnfonction n'accepte pas un argument de chaîne de format. Vous dites qu'une constante globale est meilleure mais n'avez pas justifié pourquoi elle est meilleure que la réponse marquée. Vous avez créé une étiquette non standard pour une chaîne de format bien connue. L'étiquette est beaucoup plus longue, plus difficile à retenir et personne d'autre qui travaille sur votre code ne l'utilisera. Il utilise à la fois ALL_CAPS et un trait de soulignement dont tout linter golang se plaindra. La convention est mixedCaps golang.org/doc/effective_go.html#mixed-caps Il vaut probablement mieux supprimer cette réponse.
Davos