Как распечатать структурные переменные в консоли?


381

Как я могу напечатать (в консоли) Id, Title, Nameи т.д. этой структуры в 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-

Ответы:


641

Чтобы напечатать название полей в структуре:

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

Из fmtпакета :

при печати структур, флаг плюс ( %+v) добавляет имена полей

Это предполагает, что у вас есть экземпляр Project (в ' yourProject')

В статье JSON and Go будет дано больше подробностей о том, как извлечь значения из структуры JSON.


Эта страница Go by example предоставляет другую технику:

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 ... поэтому я не хочу устанавливать Id или Name, я просто хочу получить его поверх API и распечатать в консоли. Как я могу это сделать?
фнр

4
@fnr Если у вас есть документ в формате JSON, вам нужно удалить его, прежде чем вы сможете напечатать его поле.
VonC

3
Upvoted! Моя единственная жалоба - команда% + v не очень хорошо печатает! Я все еще доволен эффективностью этой линии.
Шадониня,

1
Нужно сделать импорт «encoding / json» для техники json marshalling,
Джим Хоагленд

1
Обратите внимание, что .Printf ("% + v \ n") также работает с пакетом "log"
Ариэль Монако

140

Я хочу порекомендовать 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
Вы можете добавить функцию разыменования, которая есть у go-spew. Это позволяет вам печатать значение структуры, на которую ссылается указатель, а не указатель itsel

Большим профессионалом с использованием spew является то, что вывод уже хорошо отформатирован, так что вы можете легко проверить все свойства объекта.
Катушка

97

мой 2cents должен был бы использовать json.MarshalIndent- удивленный, это не предложено, поскольку это является самым прямым. например:

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

нет внешних депов и приводит к красиво отформатированному выводу.


2
Интересный вариант. +1
VonC

1
Именно то, что я искал. Легкая красивая печать с повторным использованием встроенной библиотеки JSON.
AdmiralThrawn

Если не нужно печатать тип и длину поля (Spew отлично подходит для этого), это решение является лучшим, так как указатели также правильно напечатаны!
Кристоф Видаль

👏🏻 Коротко и сладко. Вы можете заменить "\t"на, " "если вместо этого хотите сделать отступ в пространстве
Дана Вудман

1
Следует отметить, что Marshal()только сериализует экспортируемые поля структуры - это идеально подходит для карт, хотя.
nobar

24

Я думаю, что было бы лучше реализовать пользовательский стрингер, если вы хотите какой-то форматированный вывод 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

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, просто ссылка, указатель или литерал созданной вами структуры.

Для использования просто возьмите свою структуру, инициализируйте ее в основном или любом другом пакете, в котором вы находитесь, и передайте его в 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

Я рекомендую использовать Pretty Printer Library . В этом вы можете распечатать любую структуру очень легко.

  1. Установить библиотеку

    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
Константин Тихонов

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

Другой способ - создать функцию с именем toStringstruct, которая принимает структуру, форматировать поля по своему усмотрению.

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

очень просто у меня нет структуры данных и коммитов, поэтому я изменил

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 (интерфейс arg {}, глагол 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» в пакете с именем «commons» (возможно) и использовать ее повсюду в вашем коде.

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

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

3
Вежливо, люди проголосовали против этого, потому что Printlnфункция не принимает аргумент строки формата. Вы говорите, что глобальная константа лучше, но не обосновывает, почему она лучше, чем отмеченный ответ. Вы создали нестандартную метку для хорошо известной строки формата. Метка намного длиннее, ее труднее запомнить, и никто, кто работает над вашим кодом, не будет ее использовать. Он использует как ALL_CAPS, так и символ подчеркивания, на который будет жаловаться каждый golang linter. Соглашение mixedCaps гласит golang.org/doc/effective_go.html#mixed-caps Вероятно, лучше всего удалить этот ответ.
Давос
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.