Bagaimana cara mencetak variabel struct di konsol?


380

Bagaimana saya bisa mencetak (di konsol) yang Id, Title, Name, dll dari struct ini di 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
Semuanya, untuk debugging? Coba fmt.Println.
Ry-

Jawaban:


641

Untuk mencetak nama bidang dalam sebuah struct:

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

Dari fmtpaket :

saat mencetak struct, tanda tambah ( %+v) menambahkan nama bidang

Itu seandainya Anda memiliki instance dari Proyek (dalam ' yourProject')

Artikel JSON dan Go akan memberikan rincian lebih lanjut tentang cara mengambil nilai dari struct JSON.


Halaman Go by example ini menyediakan teknik lain:

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

Itu akan mencetak:

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

Jika Anda tidak memiliki instance, maka Anda perlu menggunakan refleksi untuk menampilkan nama bidang struct yang diberikan, seperti dalam contoh ini .

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
Terima kasih atas jawaban Anda tetapi ada satu hal lagi. File JSON saya terkait dengan API ... karenanya saya tidak ingin mengatur Id atau Nama, saya hanya ingin mendapatkannya di atas API dan mencetaknya di konsol. Bagaimana saya bisa melakukan itu?
fnr

4
@ fnr Jika Anda memiliki dokumen JSON, Anda harus mengosongkannya, sebelum dapat mencetak bidangnya.
VonC

3
Terpilih! Satu keluhan saya adalah perintah% + v tidak cukup mencetaknya! Saya masih senang dengan efisiensi saluran ini.
Shadoninja

1
Perlu melakukan impor "penyandian / json" untuk teknik json marshalling,
Jim Hoagland

1
Perhatikan bahwa .Printf ("% + v \ n") juga berfungsi dengan paket "log"
Ariel Monaco

139

Saya ingin merekomendasikan go-spew , yang menurut github mereka "Menerapkan printer yang cukup dalam untuk struktur data Go untuk membantu debugging"

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

contoh penggunaan:

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

keluaran:

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

5
Anda bisa menambahkan fitur dereference yang dimiliki oleh go-spew. Ini memungkinkan Anda untuk mencetak nilai struct di mana pointer merujuk dan bukan pointer

Pro besar dengan menggunakan memuntahkan adalah bahwa output sudah diformat dengan baik sehingga Anda dapat dengan mudah memeriksa semua properti objek.
COil

97

2 sen saya akan digunakan json.MarshalIndent- terkejut ini tidak disarankan, karena ini adalah yang paling mudah. sebagai contoh:

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

tidak ada deps eksternal dan menghasilkan output yang diformat dengan baik.


2
Opsi menarik. +1
VonC

1
Persis apa yang saya cari. Pencetakan cantik yang mudah dengan penggunaan kembali built in json library.
AdmiralThrawn

Kecuali seseorang perlu mencetak jenis dan panjang bidang (Spew hebat untuk itu), solusi ini adalah yang terbaik karena Pointer juga dicetak dengan benar!
Christophe Vidal

👏🏻 Pendek dan manis. Anda dapat menggantinya "\t"dengan " "jika Anda menginginkan indentasi ruang
Dana Woodman

1
Sebagai catatan, Marshal()hanya serialisasi bidang yang diekspor dari struct - namun sangat cocok untuk peta.
Nobar

24

Saya pikir akan lebih baik untuk menerapkan stringer kustom jika Anda ingin semacam output yang diformat dari struct

sebagai contoh

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), melempar saya main.structdengan struct type apa perbedaan antara "%#v"dan "%+v"@cokebol
muthukumar helius

13

Atau, coba gunakan fungsi ini 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)
}

Untuk menggunakan ini, Anda tidak perlu paket tambahan dengan pengecualian fmtdan encoding/json, hanya referensi, pointer ke, atau literal dari struct yang telah Anda buat.

Untuk menggunakan, ambil saja struct Anda, inisialisasinya dalam paket utama atau apa pun yang Anda masuki dan berikan 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)
}

Keluarannya adalah

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

Main-main dengan kode di sini .


5

Saya suka sampah .

Dari readme mereka:

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

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

Sdump sangat berguna dalam tes:

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

Saya merekomendasikan untuk menggunakan Perpustakaan Pretty Printer . Anda dapat mencetak struct dengan sangat mudah.

  1. Instal Perpustakaan

    https://github.com/kr/pretty

atau

go get github.com/kr/pretty

Sekarang lakukan seperti ini dalam kode Anda

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.

}

Anda juga bisa mendapatkan perbedaan antara komponen melalui perpustakaan ini dan banyak lagi. Anda juga dapat melihat pustaka Documents di sini.


1
Akan sangat membantu untuk melihat contoh output yang dihasilkan olehpretty.Formatter
Konstantin Tikhonov

4

Ketika Anda memiliki struktur yang lebih kompleks, Anda mungkin perlu mengonversi ke JSON sebelum mencetak:

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

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


3

Kunjungi di sini untuk melihat kode lengkap. Di sini Anda juga akan menemukan tautan untuk terminal daring tempat kode lengkap dapat dijalankan dan program tersebut menunjukkan cara mengekstraksi informasi struktur (beri isian jenis & nilainya). Di bawah ini adalah cuplikan program yang hanya mencetak nama bidang.

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

Ada juga go-render , yang menangani rekursi pointer dan banyak pemilahan kunci untuk string dan peta int.

Instalasi:

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

Contoh:

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

Yang mencetak:

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)

Ini adalah cara dasar untuk mencetak detail


0

Cara lain adalah, buat fungsi toStringyang membutuhkan struct, format bidang seperti yang Anda inginkan.

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
Atau Anda bisa mengimplementasikan Stringerantarmuka. Akan terlihat seperti ini: 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

Tanpa menggunakan perpustakaan eksternal dan dengan baris baru setelah setiap bidang:

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

sangat sederhana Saya tidak memiliki struktur Data dan Komit. Jadi saya mengubah

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

Untuk belajar, Anda dapat mengambil bantuan dari sini: https://gobyexample.com/structs


0

Mungkin ini seharusnya tidak diterapkan untuk permintaan produksi tetapi jika Anda berada pada mode debugging saya sarankan Anda mengikuti pendekatan di bawah ini.

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

Ini menghasilkan format data dalam format json dengan peningkatan keterbacaan.



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

Cara yang lebih baik untuk melakukan ini adalah membuat konstanta global untuk string "% + v" dalam paket yang disebut "commons" (mungkin) dan menggunakannya di mana saja dalam kode Anda

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

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

3
Secara sopan, orang telah memilih ini karena Printlnfungsinya tidak menerima argumen format string. Anda mengatakan konstanta global lebih baik tetapi belum membenarkan mengapa itu lebih baik daripada jawaban yang ditandai. Anda telah membuat label tidak standar untuk string format yang terkenal. Label jauh lebih lama, lebih sulit untuk diingat dan tidak ada orang lain yang bekerja pada kode Anda yang akan menggunakannya. Ini menggunakan ALL_CAPS dan garis bawah yang akan dikeluhkan oleh setiap golang. Konvensi ini adalah mixedCaps golang.org/doc/effective_go.html#mixed-caps Mungkin yang terbaik untuk menghapus jawaban ini.
Davos
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.