How to dereference fields when printing?
Asked Answered
B

4

21

http://play.golang.org/p/joEmjQdMaS

package main

import "fmt"

type SomeStruct struct {
    somePointer *somePointer
}
type somePointer struct {
    field string
}

func main() {
    fmt.Println(SomeStruct{&somePointer{"I want to see what is in here"}})
}

This prints a memory address like this {0x10500168}

Is there a way to make it print:

{{"I want to see what is in here"}}

This is mostly for debugging purposes, if I had a struct with 30 pointer fields, I didn't want to have to do a println for each of the 30 fields to see what is in it.

Befog answered 7/1, 2014 at 20:12 Comment(3)
I suspect there's not any easy way (Println would have to track circular pointers if it could chase pointers like that), you'll have to implement func (p *SomeStruct) String() string; for the outer SomeStuctTetrastich
fmt.Printf("%+v", SomeStruct{&somePointer{"I want to see what is in here"}}) by using the %+v it prints out all the attributes with their names. If you just do %v it will show only the valuesCallus
Actually I might have been wrong, its showing you the value as a memory location because you are passing it by reference &somePointer{"Callus
O
23

There is a great package called go-spew. Does exactly what you want.

package main

import (
  "github.com/davecgh/go-spew/spew"
)

type (
  SomeStruct struct {
    Field1 string
    Field2 int
    Field3 *somePointer
  }
  somePointer struct {
    field string
  }
)

func main() {
  s := SomeStruct{
    Field1: "Yahoo",
    Field2: 500,
    Field3: &somePointer{"I want to see what is in here"},
  }
  spew.Dump(s)

}

Will give you this output:

(main.SomeStruct) {
 Field1: (string) "Yahoo",
 Field2: (int) 500,
 Field3: (*main.somePointer)(0x2102a7230)({
  field: (string) "I want to see what is in here"
 })
}
Olimpia answered 1/3, 2014 at 22:39 Comment(2)
Wow, didn't know about this package. Nice!Susiesuslik
This is an incredible library. The exact thing I needed and it was very easy to implement.Laclos
N
2
package main

import (
    "fmt"
)


type SomeTest struct {
    someVal string
}

func (this *SomeTest) String() string {
    return this.someVal
}

func main() {
    fmt.Println(&SomeTest{"You can see this now"})
}

Anything that provides the Stringer interface will be printed with it's String() method. To implement stringer, you only need to implement String() string. To do what you want, you'd have to implement Stringer for SomeStruct (in your case, dereference somePointer and do something with that).

Norwegian answered 7/1, 2014 at 21:38 Comment(3)
I was going to answer the same thing, but it turns out that if you wrap the type in an outer struct, it still just prints the pointer: play.golang.org/p/6P4ol8SS8o.Cabdriver
@joshlf13 My suggestion was actually to just to implement String himself to get the behavior he wants. Maybe there's a more elegant solution, but this one definitely works.Norwegian
If the downvoter could please explain what he thinks is wrong with this answer? It's certainly not magical, but it works.Norwegian
J
2

You're attempting to print a struct that contains a pointer. When you print the struct, it's going to print the values of the types contained - in this case the pointer value of a string pointer.

You can't dereference the string pointer within the struct because then it's no longer accurately described by the struct and you can't dereference the struct because it's not a pointer.

What you can do is dereference the string pointer, but not from within the struct.

func main() {
    pointer := SomeStruct{&somePointer{"I want to see what is in here"}}.somePointer
    fmt.Println(*pointer)
}

output: {I want to see what is in here}

You can also just print the specific value from within the Println:

func main() {
    fmt.Println(SomeStruct{&somePointer{"I want to see what is in here"}}.somePointer)
}

output: &{I want to see what is in here}

Another thing to try is Printf:

func main() {
    structInstance := SomeStruct{&somePointer{"I want to see what is in here"}}
    fmt.Printf("%s",structInstance)
}

output: {%!s(*main.somePointer=&{I want to see what is in here})}

Judaic answered 9/12, 2016 at 20:12 Comment(0)
S
0

Depending on your use-case, json.Marshal will get you a long way. In the example shown fields would need to be exported:

package main

import (
    "encoding/json"
    "fmt"
)

type SomeStruct struct {
    SomePointer *somePointer
}
type somePointer struct {
    Field string
}

func main() {
    s := SomeStruct{&somePointer{"I want to see what is in here"}}
    b, _ := json.Marshal(s)

    fmt.Println(string(b))
}

// > {"SomePointer":{"Field":"I want to see what is in here"}}```

My use-case was printing a slice of pointers of different types returned from *sql.Rows Scan:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    i := 1
    s := "foo"
    b := true

    a := []any{&i, &s, &b}

    j, _ := json.Marshal(a)

    fmt.Println(string(j))
}

// > [1,"foo",true]
Scullion answered 4/6, 2024 at 3:25 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.