abw333
abw333

Reputation: 5961

How can I get the string representation of a struct?

For my application, it does not matter if the string is human readable or not.

Upvotes: 139

Views: 232657

Answers (6)

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48723

You can strap a String() method onto the struct to tell Go how to display your struct.

Here is how you would implement the String() function for a struct:

package main

import "fmt"

// Vertex2D represents a point in 2D space.
type Vertex2D struct {
    X, Y float64
}

// Returns a string representation of Vertex2D in the format "(X, Y)".
// It implements the fmt.Stringer interface.
func (v Vertex2D) String() string {
    return fmt.Sprintf("(%.2f, %.2f)", v.X, v.Y)
}

func main() {
    v := Vertex2D{X: 1.0, Y: 2.0}

    // Output without Vertex2D.String() defined
    // The default output for structs uses the Go syntax representation.
    // fmt.Println(v)          // {1 2}
    // fmt.Printf("%v\n", v)   // {1 2}
    // fmt.Printf("%+v\n", v)  // {X:1 Y:2}

    // Output with Vertex2D.String() defined
    // The custom String method provides a more readable output.
    fmt.Println(v)         // (1.00, 2.00)
    fmt.Printf("%v\n", v)  // (1.00, 2.00)
    fmt.Printf("%+v\n", v) // (1.00, 2.00)
}

For more info, check out the fmt module.


Here is the Stringer interface from the fmt package.

// Stringer is implemented by any value that has a String method,
// which defines the “native” format for that value.
// The String method is used to print values passed as an operand
// to any format that accepts a string or to an unformatted printer
// such as Print.
type Stringer interface {
    String() string
}

Here is where it is checked in the private handleMethods function, during printing:

func (p *pp) handleMethods(verb rune) (handled bool) {
    // ...
    if p.fmt.sharpV {
        // ...
    } else {
        switch verb {
        case 'v', 's', 'x', 'X', 'q':
            switch v := p.arg.(type) {
            // ...
            case Stringer:
                // ...
                p.fmtString(v.String(), verb) // <-- Called here
                return
            }
        }
    }
    return false
}

Upvotes: 0

Arghyadeb
Arghyadeb

Reputation: 478

Attaching a String() function to a named struct allows us to convert a struct to a string.

package main

import "fmt"

type Foo struct {
    Bar string
}

func (f Foo) String() string {
    return fmt.Sprintf("Foo says: %q", f.Bar)
}

func main() {
    fmt.Println(Foo{Bar: "Hello World!"})
}

Output:

Foo says: "Hello World!"

Upvotes: 23

xu feng
xu feng

Reputation: 129

Using json or fmt.Sprintf, I make a benchmark,

BenchmarkStructJson-8            1000000          1773 ns/op
BenchmarkStructSprintSharp-8      200000          6139 ns/op
BenchmarkStructSprint-8           500000          2763 ns/op
BenchmarkStructSprintPlus-8       300000          4373 ns/op

BenchmarkStructJson is using json.Marshal @Matheus Santana

BenchmarkStructSprintSharp: fmt.Sprintf("%#v", &a) @Ask Bjørn Hansen

BenchmarkStructSprint: fmt.Sprintf("%v", &a)

BenchmarkStructSprintPlus: fmt.Sprintf("%+v", &a)

The result is, json.Marshal is better performance.

Upvotes: 3

Santosh Pillai
Santosh Pillai

Reputation: 8663

you can also add a function with that struct receiver.

// URL : Sitemap Xml
type URL struct {
    Loc string `xml:"loc"`
}

// URLSET : Sitemap XML
type URLSET struct {
    URLS []URL `xml:"url"`
}

// converting the struct to String format. 
func (u URL) String() string {
    return fmt.Sprintf(u.Loc)
}

So printing this struct field will return a string.

fmt.Println(urls.URLS)

Upvotes: 11

ANisus
ANisus

Reputation: 78065

One popular way of encoding structs into strings is using JSON.

You have certain limitations such as not getting all the information (such as the specific type of each field), only serializing exported fields, and not handling recursive values. But it is a simple standard way of serializing data.

Working example:

package main

import (
    "fmt"
    "encoding/json"
)

type s struct {
    Int       int
    String    string
    ByteSlice []byte
}

func main() {
    a := &s{42, "Hello World!", []byte{0,1,2,3,4}}

    out, err := json.Marshal(a)
    if err != nil {
        panic (err)
    }

    fmt.Println(string(out))
}

Give this output:

{"Int":42,"String":"Hello World!","ByteSlice":"AAECAwQ="}

https://play.golang.org/p/sx-xdSxAOG

Upvotes: 139

Ask Bj&#248;rn Hansen
Ask Bj&#248;rn Hansen

Reputation: 6953

If it's a "one way" serialization (for debugging or logging or whatever) then fmt.Printf("%#v", var) is very nice. (Update: to put the output into a string instead of printing it, use str := fmt.Sprintf("%#v", var).

If size matters you can use %v, but I like %#v because it will also include the field names and the name of the struct type.

A third variation is %+v which will include the field names, but not the struct type.

They are all documented at the top of the fmt documentation.

If you need two-way serialization JSON, Gob or XML are the easiest/built-in options in Go, see the encoding packages.

Upvotes: 169

Related Questions