วิธีพิมพ์ตัวแปร struct ในคอนโซล?


379

ฉันสามารถพิมพ์ (ในคอนโซลน) Id, Title, Nameฯลฯ ของ struct นี้ใน 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
ทั้งหมดของพวกเขาสำหรับการแก้ไขข้อบกพร่อง? ลองfmt.Printlnดู
Ry-

คำตอบ:


639

หากต้องการพิมพ์ชื่อของฟิลด์ใน struct:

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

จากfmtแพคเกจ :

เมื่อพิมพ์ structs เครื่องหมายบวก ( %+v) จะเพิ่มชื่อฟิลด์

สมมติว่าคุณมีอินสแตนซ์ของโครงการ (ใน ' yourProject')

บทความJSON และ Goจะให้รายละเอียดเพิ่มเติมเกี่ยวกับวิธีดึงค่าจากโครงสร้าง JSON


ไปตามตัวอย่างหน้านี้มีเทคนิคอื่น:

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

ที่จะพิมพ์:

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

หากคุณไม่มีอินสแตนซ์ใด ๆ คุณต้องใช้การสะท้อนเพื่อแสดงชื่อของฟิลด์ของโครงสร้างที่กำหนดดังเช่นในตัวอย่างนี้

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
ขอบคุณสำหรับคำตอบของคุณ แต่มีอีกอย่างหนึ่ง ไฟล์ JSON ของฉันเกี่ยวข้องกับ API ... ดังนั้นฉันไม่ต้องการตั้งรหัสหรือชื่อฉันแค่ต้องการรับมันผ่าน API และพิมพ์ในคอนโซล ฉันจะทำสิ่งนั้นได้อย่างไร
fnr

4
@fnr หากคุณมีเอกสาร JSON คุณจะต้องยกเลิกการเปิดเอกสารก่อนจึงจะสามารถพิมพ์ฟิลด์ได้
VonC

3
upvoted! การร้องเรียนเดียวของฉันคือคำสั่ง% + v ไม่น่าพิมพ์ ฉันยังมีความสุขกับประสิทธิภาพของบรรทัดนี้
Shadoninja

1
จำเป็นต้องทำการนำเข้า "การเข้ารหัส / json" สำหรับเทคนิค json marshalling
Jim Hoagland

1
โปรดทราบว่า. Printf ("% + v \ n") สามารถใช้งานได้กับแพ็คเกจ "บันทึก"
Ariel Monaco

139

ฉันต้องการแนะนำgo-spewซึ่งตาม github ของพวกเขา "ใช้เครื่องพิมพ์สวยลึกสำหรับโครงสร้างข้อมูล Go เพื่อช่วยในการแก้ไขข้อบกพร่อง"

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

ตัวอย่างการใช้งาน:

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

เอาท์พุท:

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

5
คุณสามารถเพิ่มฟีเจอร์ dereference ที่ go-spew อนุญาตให้คุณพิมพ์ค่าของ struct ที่ตัวชี้อ้างอิงและไม่ใช่ตัวชี้

โปรใหญ่ที่มีการใช้งาน spew คือเอาต์พุตมีการจัดรูปแบบเรียบร้อยแล้วดังนั้นคุณสามารถตรวจสอบคุณสมบัติของวัตถุทั้งหมดได้อย่างง่ายดาย
ขด

97

2 เซ็นต์ของฉันจะใช้json.MarshalIndent- ประหลาดใจนี้ไม่แนะนำเพราะมันตรงไปตรงมาที่สุด ตัวอย่างเช่น:

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

ไม่มีค่าใช้จ่ายภายนอกและผลลัพธ์ในเอาต์พุตที่จัดรูปแบบเป็นอย่างดี


2
ตัวเลือกที่น่าสนใจ +1
VonC

1
สิ่งที่ฉันกำลังมองหา พิมพ์ง่ายสวยด้วยการสร้างใหม่ในไลบรารี json
AdmiralThrawn

ถ้าไม่มีใครต้องการพิมพ์ประเภทและความยาวของเขตข้อมูล (Spew นั้นยอดเยี่ยมสำหรับเรื่องนั้น) โซลูชันนี้ดีที่สุดเนื่องจาก Pointers นั้นถูกพิมพ์อย่างถูกต้องด้วย!
Christophe Vidal

👏🏻สั้นและหวาน คุณสามารถแทนที่"\t"ด้วย" "ถ้าคุณต้องการเว้นวรรคเยื้องแทน
Dana Woodman

1
โปรดทราบว่าMarshal()มีเฉพาะเขตข้อมูลที่ส่งออกเป็นโครงสร้างเท่านั้นซึ่งเป็นที่สมบูรณ์แบบสำหรับแผนที่
nobar

24

ฉันคิดว่ามันจะเป็นการดีกว่าถ้าคุณใช้ Stringer ที่กำหนดเองหากคุณต้องการเอาท์พุทที่จัดรูปแบบบางอย่าง struct

ตัวอย่างเช่น

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)โยนฉันmain.structมีstruct type สิ่งที่เป็นความแตกต่างระหว่าง"%#v"และ"%+v"@cokebol
Helius muthukumar

13

หรือลองใช้ฟังก์ชั่นนี้ 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)
}

ในการใช้งานนี้คุณไม่จำเป็นต้องมีแพ็คเกจเพิ่มเติมยกเว้นfmtและencoding/jsonเพียงแค่การอ้างอิงตัวชี้ไปที่หรือตัวอักษรของโครงสร้างที่คุณสร้างขึ้น

ที่จะใช้เพียงแค่ใช้เวลา struct 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)
}

มันจะเป็นผลลัพธ์

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

เล่นรอบกับรหัสที่นี่


5

ฉันชอบครอก

จาก readme ของพวกเขา

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

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

Sdump ค่อนข้างมีประโยชน์ในการทดสอบ:

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

ผมแนะนำให้ใช้ห้องสมุดเครื่องพิมพ์พริตตี้ ในสิ่งที่คุณสามารถพิมพ์ struct ใด ๆ ได้อย่างง่ายดาย

  1. ติดตั้ง Library

    https://github.com/kr/pretty

หรือ

go get github.com/kr/pretty

ตอนนี้ทำเช่นนี้ในรหัสของคุณ

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.

}

นอกจากนี้คุณยังสามารถรับความแตกต่างระหว่างองค์ประกอบผ่านไลบรารีนี้และอีกมากมาย นอกจากนี้คุณยังสามารถดูเอกสารของห้องสมุดได้ที่นี่


1
จะเป็นประโยชน์ในการดูตัวอย่างผลลัพธ์ที่สร้างโดยpretty.Formatter
Konstantin Tikhonov

4

เมื่อคุณมีโครงสร้างที่ซับซ้อนมากขึ้นคุณอาจต้องแปลงเป็น JSON ก่อนทำการพิมพ์:

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

ที่มา: https://gist.github.com/tetsuok/4942960


3

เยี่ยมชมที่นี่เพื่อดูรหัสที่สมบูรณ์ ที่นี่คุณจะพบลิงค์สำหรับเทอร์มินัลออนไลน์ที่สามารถเรียกใช้รหัสที่สมบูรณ์และโปรแกรมจะแสดงวิธีดึงข้อมูลโครงสร้าง (ชื่อของฟิลด์ประเภทและค่า) ด้านล่างนี้เป็นข้อมูลโค้ดของโปรแกรมที่พิมพ์ชื่อฟิลด์เท่านั้น

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

นอกจากนี้ยังมีgo-renderซึ่งจัดการการเรียกซ้ำตัวชี้และการเรียงลำดับคีย์จำนวนมากสำหรับสตริงและแมปแผนที่

การติดตั้ง:

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

ตัวอย่าง:

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

สิ่งที่พิมพ์:

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


0

อีกวิธีหนึ่งคือสร้าง func ที่เรียกtoStringว่าใช้โครงสร้างจัดรูปแบบเขตข้อมูลตามที่คุณต้องการ

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
หรือคุณสามารถใช้Stringerอินเตอร์เฟสได้ มันจะมีลักษณะเช่นนี้: 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

โดยไม่ต้องใช้ไลบรารีภายนอกและขึ้นบรรทัดใหม่หลังจากแต่ละฟิลด์:

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

ง่ายมากฉันไม่มีโครงสร้างของ Data และ Commits ดังนั้นฉันจึงเปลี่ยน

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

เพื่อการเรียนรู้คุณสามารถรับความช่วยเหลือได้จากที่นี่: https://gobyexample.com/structs


0

อาจไม่เหมาะสำหรับคำขอการผลิต แต่ถ้าคุณอยู่ในโหมดแก้ไขข้อบกพร่องฉันขอแนะนำให้คุณทำตามวิธีการด้านล่าง

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

ซึ่งส่งผลในการจัดรูปแบบข้อมูลในรูปแบบ json ด้วยการอ่านเพิ่มขึ้น


-2

แพ็คเกจเหล่านี้ส่วนใหญ่ใช้แพ็คเกจการสะท้อนเพื่อให้สามารถทำสิ่งนั้นได้

ป้อนคำอธิบายรูปภาพที่นี่

fmt.Sprintf () ใช้ -> func (p * pp) printArg (อินเตอร์เฟสส่วนต่อท้าย {}, verb rune) ของ lib มาตรฐาน

ไปที่บรรทัด 638 -> https://golang.org/src/fmt/print.go

การสะท้อน:

https://golang.org/pkg/reflect/

รหัสตัวอย่าง:

https://github.com/donutloop/toolkit/blob/master/debugutil/prettysprint.go


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

วิธีที่ดีกว่าในการทำเช่นนี้คือการสร้างค่าคงที่ทั่วโลกสำหรับสตริง "% + v" ในแพ็คเกจที่เรียกว่า "คอมมอนส์" (อาจ) และใช้งานได้ทุกที่ในรหัสของคุณ

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

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

3
ผู้คนลงคะแนนอย่างสุภาพเพราะPrintlnฟังก์ชั่นไม่ยอมรับอาร์กิวเมนต์สตริงรูปแบบ คุณบอกว่าค่าคงที่ทั่วโลกดีกว่า แต่ไม่ได้พิสูจน์ว่าทำไมมันถึงดีกว่าคำตอบที่ทำเครื่องหมายไว้ คุณได้สร้างป้ายกำกับที่ไม่ได้มาตรฐานสำหรับสตริงรูปแบบที่รู้จักกันดี ป้ายกำกับนั้นยาวกว่าจำได้ยากกว่าและไม่มีใครทำงานกับรหัสของคุณได้ มันใช้ทั้ง ALL_CAPS และเครื่องหมายขีดล่างซึ่ง linter golang ทุกตัวจะบ่น การประชุมคือmixedCaps golang.org/doc/effective_go.html#mixed-capsน่าจะดีที่สุดในการลบคำตอบนี้
Davos
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.