How can I get the string representation of a struct?
Asked Answered
D

5

132

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

Dripping answered 2/5, 2013 at 5:39 Comment(1)
Are you trying to serialize a struct? You should really use gob for that.Tiltyard
S
136

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

Syllogistic answered 2/5, 2013 at 6:11 Comment(3)
Exactly what I needed! +1 to youDripping
I noticed you second question and what purpose you have. JSON can be useful, but not if the output string is to be used to create a hash to test equality. You will have problems with maps, as Ask mentioned. This goes for using fmt.Sprintf as well.Syllogistic
Didn't know that keys have to be capitalized in order to be show in JSON.Bustee
W
158

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.

Whiskey answered 2/5, 2013 at 7:45 Comment(3)
Thanks for your response. I should have probably specified in my question that I'm looking to get the value in my program, not the console. In particular, I would like to then convert the string into a byte array. When I do "[]byte(fmt.Printf("%v", var))", the program complains about "multiple-value fmt.Printf() in single-value context". I'm assuming this is because Printf does not return the string value, but only prints it to the console. Do you know of a way to fix this.Dripping
I figured out how to do this using ANisus's response, but +1 to you for a good answer.Dripping
If you need it in the program use fmt.Sprintf instead of Printf. If you use JSON, beware that map values might not be returned in the same order on each run (though that might be the case for the fmt printf, too, I haven't checked).Bengt
S
136

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

Syllogistic answered 2/5, 2013 at 6:11 Comment(3)
Exactly what I needed! +1 to youDripping
I noticed you second question and what purpose you have. JSON can be useful, but not if the output string is to be used to create a hash to test equality. You will have problems with maps, as Ask mentioned. This goes for using fmt.Sprintf as well.Syllogistic
Didn't know that keys have to be capitalized in order to be show in JSON.Bustee
S
18

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: %s", f.bar)
}

func main() {
    fmt.Println(foo{"Hello World!"})
}
output:
Foo Says: Hello World!
Slav answered 5/8, 2019 at 11:7 Comment(0)
S
10

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)
Snicker answered 24/7, 2018 at 12:8 Comment(2)
A working copy of this code is here play.golang.org/p/SCDnaMFQLJc.Piny
working code is nice, should add: fmt.Printf("%s\n", URL{"Test"}); notice that the Printf() is smart enough to call String() on the struct instance.Iceland
P
3

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.

Pearlinepearlman answered 6/9, 2019 at 3:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.