Jak wydrukować zmienne struktur w konsoli?

379

Jak mogę wydrukować (w konsoli) Id, Title, Name, itd. Z tej struktury w 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
źródło
2
Wszystkie do debugowania? Spróbować fmt.Println.
Ry-

Odpowiedzi:

639

Aby wydrukować nazwę pól w strukturze:

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

Z fmtpaczki :

podczas drukowania struktur, flaga plus ( %+v) dodaje nazwy pól

To znaczy, że masz instancję projektu (w „ yourProject”)

Artykuł JSON i Go poda więcej szczegółów na temat pobierania wartości ze struktury JSON.


Ta strona z przykładami zawiera inną technikę:

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

To by wydrukowało:

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

Jeśli nie masz żadnej instancji, musisz użyć refleksji, aby wyświetlić nazwę pola danej struktury, jak w tym przykładzie .

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
źródło
1
Dziękuję za odpowiedź, ale jest jeszcze jedna rzecz. Moje pliki JSON są powiązane z interfejsem API ... dlatego nie chcę ustawiać identyfikatora ani nazwy, chcę tylko pobrać je przez interfejs API i wydrukować w konsoli. Jak mogę to zrobić?
FNR
4
@fnr Jeśli masz dokument JSON, musisz go odznaczyć, zanim będziesz mógł wydrukować jego pole.
VonC
3
Pozytywne! Moją jedyną skargą jest to, że polecenie% + v raczej go nie drukuje! Nadal jestem zadowolony z wydajności tej linii.
Shadoninja,
1
Konieczne jest zaimportowanie „kodowania / jsona” dla techniki json marshalling,
Jim Hoagland,
1
Zauważ, że .Printf („% + v \ n”) działa również z pakietem „log”
Ariel Monaco
139

Chcę polecić go-spew , który zgodnie z ich githubem „Implementuje bardzo ładną drukarkę dla struktur danych Go, aby pomóc w debugowaniu”

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

przykład użycia:

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

wynik:

(main.Project) {
 Id: (int64) 0,
 Title: (string) (len=5) "world",
 Name: (string) (len=5) "hello",
 Data: (string) "",
 Commits: (string) ""
}
Martin Olika
źródło
5
możesz dodać funkcję dereferencji, którą posiada go-spew. Pozwala wydrukować wartość struktury, do której odnosi się wskaźnik, a nie wskaźnik
Wielkim profesjonalistą z użyciem spew jest to, że dane wyjściowe są już dobrze sformatowane, dzięki czemu można łatwo sprawdzić wszystkie właściwości obiektu.
Cewka
97

moje 2 centy byłyby użyteczne json.MarshalIndent- zdziwione, że nie jest to sugerowane, ponieważ jest najprostsze. na przykład:

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

brak zewnętrznych dep i skutkuje ładnie sformatowanym wyjściem.

mad.meesh
źródło
2
Ciekawa opcja. +1
VonC,
1
Dokładnie tego szukałem. Łatwe drukowanie z ponownym użyciem wbudowanej biblioteki json.
AdmiralThrawn
O ile nie trzeba drukować typu i długości pola (Spew jest do tego świetny), to rozwiązanie jest najlepsze, ponieważ wskaźniki są również poprawnie drukowane!
Christophe Vidal,
👏🏻 Krótki i słodki. Można wymienić "\t"ze " "jeśli chcesz przestrzeń wcięcia zamiast
Dana Woodman
1
Warto zauważyć, Marshal()że serializuje tylko wyeksportowane pola struktury - jest to jednak idealne rozwiązanie do map.
nobar
24

Myślę, że lepiej byłoby zaimplementować niestandardowy stringer, jeśli chcesz jakiegoś sformatowanego wyjścia struct

na przykład

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
źródło
18
p = Project{...}
fmt.Printf("%+v", p)
fmt.Printf("%#v", p) //with type
CokeboL
źródło
2
fmt.Printf(%#v, p), Wyrzuca mnie main.structz struct type tego, co jest różnica między "%#v"i "%+v"@cokebol
muthukumar Helius
13

Alternatywnie spróbuj użyć tej funkcji 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)
}

Aby tego użyć, nie potrzebujesz żadnych dodatkowych pakietów, z wyjątkiem fmti encoding/json, tylko odniesienie, wskaźnik do lub dosłownie utworzonej struktury.

Aby użyć, po prostu weź swoją strukturę, zainicjuj ją w pakiecie głównym lub w dowolnym pakiecie, w którym się znajdujesz, i przekaż ją 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)
}

Jego wyjście byłoby

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

Pobaw się z kodu tutaj .

Erik Toor
źródło
5

Lubię śmieci .

Z ich pliku Readme:

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

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

Sdump jest bardzo przydatny w testach:

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)
  }
}
co było do okazania
źródło
5

Polecam korzystać z Pretty Printer Library . Dzięki temu możesz bardzo łatwo wydrukować dowolną strukturę.

  1. Zainstaluj bibliotekę

    https://github.com/kr/pretty

lub

go get github.com/kr/pretty

Teraz zrób tak w swoim kodzie

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.

}

Ponadto można uzyskać różnicę między składnikiem za pośrednictwem tej biblioteki i tak dalej. Możesz także zajrzeć do biblioteki dokumentów tutaj.

amku91
źródło
1
Przydałby się przykład wyjścia wygenerowanego przezpretty.Formatter
Konstantina Tichonowa
4

Jeśli masz bardziej złożone struktury, przed drukowaniem może być konieczna konwersja do JSON:

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

Źródło: https://gist.github.com/tetsuok/4942960

Cassio
źródło
3

Odwiedź tutaj, aby zobaczyć pełny kod. Tutaj znajdziesz również łącze do terminala online, w którym można uruchomić cały kod, a program reprezentuje sposób wydobywania informacji o strukturze (nazwa pola, ich typ i wartość). Poniżej znajduje się fragment programu, który drukuje tylko nazwy pól.

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
źródło
2

Istnieje również go-render , który obsługuje rekurencję wskaźnika i wiele sortowania kluczy dla map ciągów i map int.

Instalacja:

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

Przykład:

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

Które wydruki:

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
źródło
1
fmt.Printf("%+v\n", project)

Jest to podstawowy sposób drukowania szczegółów

0example.com
źródło
0

Innym sposobem jest utworzenie func o nazwie toStringstrukturalnej, sformatowanie pól według własnego uznania.

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
źródło
2
Lub możesz wdrożyć Stringerinterfejs. Wyglądałoby to tak: 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

Bez użycia zewnętrznych bibliotek i nowej linii po każdym polu:

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

bardzo proste Nie mam struktury danych i zatwierdzeń, więc zmieniłem

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

Aby się uczyć, możesz uzyskać pomoc tutaj: https://gobyexample.com/structs

Ankit Malik
źródło
0

Być może nie należy tego stosować w przypadku zleceń produkcyjnych, ale jeśli jesteś w trybie debugowania, sugeruję zastosować poniższe podejście.

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

Powoduje to formatowanie danych w formacie json o zwiększonej czytelności.

Mourya Venkat
źródło
-7
fmt.Println("%+v", structure variable)

Lepszym sposobem na to byłoby utworzenie globalnej stałej dla ciągu „% + v” w pakiecie o nazwie „commons” (być może) i użycie go wszędzie w kodzie

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

//In your code everywhere
fmt.Println(commons.STRUCTURE_DATA_FMT, structure variable)
Jithendra Kumar
źródło
3
Grzecznie ludzie głosowali za tym, ponieważ Printlnfunkcja nie akceptuje argumentu formatu ciągu. Mówisz, że stała globalna jest lepsza, ale nie uzasadniłeś, dlaczego jest lepsza niż zaznaczona odpowiedź. Utworzono niestandardową etykietę dla dobrze znanego ciągu formatu. Etykieta jest znacznie dłuższa, trudniejsza do zapamiętania i nikt inny, kto pracuje nad twoim kodem, by jej nie użył. Używa zarówno ALL_CAPS, jak i podkreślenia, na które narzeka każdy golang. Konwencja to mixedCaps golang.org/doc/effective_go.html#mixed-caps Prawdopodobnie najlepiej usunąć tę odpowiedź.
Davos,