In Golang, is there an easy way to print for debugging the dereferenced pointers given a slice of pointers to structs?
If you don't want to use unsafe and an external package.. you can range over it yourself:
for _, p := range people {
fmt.Printf("%+v\n", p)
}
Output:
&{name:Simon age:25}
&{name:Bob age:31}
Working sample: http://play.golang.org/p/aVw0rhQNuk
Maybe it's a late answer, but I've just come across the same problem and wanna save my choice here for anyone needed.
I added a String() function to my item type. For example:
type SliceItem struct {
ID int32
Name string
}
func (i *SliceItem) String() string {
return fmt.Sprintf("id = %d, name = %s\n", i.ID, i.Name)
}
As a result, whenever I wanna print this item, I got friendly "id = xx, name = xxx" string, instead of unreadable pointer addresses.
If you want to print individual elements, try it with the index and asterix for dereferencing:
fmt.Println(*pointer_strcut_slice[0])
fmt.Println(*pointer_strcut_slice[1])
Related
the title of the question pretty much sums it up. I'm playing with reflections using Go, and I'm trying to get the address of what reflect.Value() is pointing at.
why?
I have a function that can receive a struct in two ways:
first.. this is the struct
type UserInfo struct {
Name string `json:"name"`
Roles *[]model.Role `json:"role"`
UserId int `json:"user_id" db:"id"`
}
one:
var userInfo types.UserInfo
myFunc(&userInfo)
with this method i'm good since since it's a pointer to a struct that has it's memory allocated
the 2nd method:
var userInfo *types.UserInfo
myFunc(userInfo)
so here if I do reflect.Value() it's a Nil Pointer.
i want to allocate that struct and to point userInfo to the new place.
now I can easily do that if I paste &userInfo as well
and perform:
myFunc(dst interface{}, dstAddr interface{})
{
v := reflect.ValueOf(dstAddr)
t := reflect.TypeOf(dst)
ptr := reflect.New(t.Type())
...
v.Elem().Set(ptr)
}
now I would except that reflect.ValueOf(dst).Addr() will be the same as reflect.ValueOf(&dst) but actually reflect.ValueOf(dst).CanAddr() returns false.
so.. is there a way to get reflect.ValueOf(&dst) while only having reflect.ValueOf(dst) ?
Whatever you pass to reflect.ValueOf() or any other function, a copy will be made.
That being said, reflect.Value(foo) cannot possibly give you back the address of the original foo, it could only give you back the address of the copy. To avoid further confusion, in this case Value.CanAddr() would return false, letting you know the address that could be returned using Value.Addr() would not be what most would expect, it wouldn't be a useful address.
As you indicated, you want to pass a single value, so pass &foo. Doing so you will be able to get the foo value pointed by &foo using Value.Elem().
Also note that the (wrapped) foo value you get by Value.Elem() will be addressable, since it was acquired from a reflect.Value wrapping &foo. So if the reflect.Value is not reflect.ValueOf(foo) but reflect.ValueOf(&foo).Elem(), you are able to get back (to) &foo.
See this example:
func main() {
var foo = 3
fmt.Println("Address:", &foo)
bar(&foo)
fmt.Println("After:", foo)
}
func bar(x interface{}) {
v := reflect.ValueOf(x)
v2 := v.Elem()
fmt.Println("Passed pointed value:", v2.Interface())
v2.Set(reflect.ValueOf(4))
fmt.Println("Address got from pointed value:", v2.Addr())
}
This will output (try it on the Go Playground):
Address: 0xc000080010
Passed pointed value: 3
Address got from pointed value: 0xc000080010
After: 4
I have a slice of struct []student, and I want to modify its content with function.
type student struct {
name string
age int
}
students := []student{
{"Doraemon", 30},
{"King Kong", 25},
}
Thus, I decided to pass it as a pointer. May I know how to pass the slice as a reference to a function?
func addAge (s *[]student) error { //this code has error
//everyone add 2 years old
for i, e := range *s {
s[i].age = s[i].age + 2
}
//make the first student much older
s[0].age = s[0].age + 5
return nil
}
I keep playing with Go Playground, but it gives many complains, such as
cannot range over s (type *[]student)
invalid operation: s[i] (type *[]student does not support indexing)
invalid indirect of s
...
How to precisely pass the reference of a slice of struct to a function? How to range the slice of struct? And how to change the value of the struct (modify the same struct in THE slice)?
I keep getting error while playing with s *[]student, range *s, s []student, s *[]*student ... so hard to get it correct...
sorry for my NEWBIE question, still learning GO... trying hard
Slices are passed by reference, so as long as you are modifying the existing slice content you should not explicitly pass a pointer.
package main
import (
"fmt"
)
type student struct {
name string
age int
}
func main() {
students := []student{
{"Doraemon", 30},
{"King Kong", 25},
}
err := addAge (students)
fmt.Println(students)
if err != nil {
fmt.Println("error")
}
}
func addAge (s []student) error {
for i, _ := range s {
s[i].age = 3
}
return nil
}
Now, for your addAdditinalStudent function you should actually use the append function. Plus, have in mind
..., since the slice header is always updated by a call to
append, you need to save the returned slice after the call. In fact,
the compiler won't let you call append without saving the result.
Slices#append
// add student
students = append(students, student{"Test", 33})
Go Playground
in Go you can pass items by value ([]student) or by reference ([]*student). When you want to operate on the values of a struct{} you should pass it to a function with its reference (the pointer).
So you can do something like this:
type student struct {
name string
age int
}
func addTwoYearsToAll(students []*student){
for _, s := range students {
s.age += 2
}
}
This way you're working with the same exact items you build when appending to the slice. Playground example.
Also take a look at Are Golang function parameter passed as copy-on-write?
A validator package gives me back strings like this if a given field in my struct doesn't pass the validation:
myString := "Stream.Fields[0].Name"
How can i use this string to gain access to the struct field specified in it? I need to reference it somehow but i have no idea where to start with.
I'm beginning to learn Go and already came across the "Reflect" package which seems to be able to do that but i don't know what to look for or how to formulate the right question.
You need to use reflect package for this.
Here I have written a sample function which given an instance and string key like Stream.Details.Name will return the Name from the field Details of instance Stream
This works for structs without array or map operators , just the . operator . You may extend this to support the [] aswell
func getValueFromStruct(keyWithDots string, object interface{}) (interface{}, error) {
keySlice := strings.Split(keyWithDots, ".")
v := reflect.ValueOf(object)
// iterate through field names ,ignore the first name as it might be the current instance name
// you can make it recursive also if want to support types like slice,map etc along with struct
for _, key := range keySlice[1:] {
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
// we only accept structs
if v.Kind() != reflect.Struct {
return nil, fmt.Errorf("only accepts structs; got %T", v)
}
v = v.FieldByName(key)
}
return v, nil
}
Here is golang play link : https://play.golang.org/p/NIRdGONZBhP
This library also exists, which might do what you want:
https://github.com/mcuadros/go-lookup
The lib uses the reflect package under the hood.
I wrote some odd code, but I'm not sure why it works and what I can learn from it. I have a slice type build from another struct. I made a function on the slice type to modify itself. To do this, I seem to have to throw around *'s a little much.
I'm trying to learn about pointers in Go and would like a little help. Here's an example (http://play.golang.org/p/roU3MEeT3q):
var ClientNames = []string {"Client A", "Client B", "ClientC"}
type InvoiceSummaries []InvoiceSummary
type InvoiceSummary struct {
Client string
Amt int
}
func (summaries *InvoiceSummaries) BuildFromAbove() {
for _, name := range ClientNames {
*summaries = append(*summaries, InvoiceSummary{name, 100})
}
}
My question is: What is the purpose for each of these * and why am I not using any &?
What is the purpose for each of these * ?
By making the method receiver as pointer, you could easily change the property of the object. I think that's one of the benefit. This example below will prove it.
package main
import "fmt"
type someStruct struct {
someVar int
}
func (s someStruct) changeVal1(newVal int) {
s.someVar = newVal
}
func (s *someStruct) changeVal2(newVal int) {
s.someVar = newVal
}
func main() {
s := someStruct{0}
fmt.Println(s) // {0}
s.changeVal1(3)
fmt.Println(s) // {0}
s.changeVal2(4)
fmt.Println(s) // {4}
(&s).changeVal2(5)
fmt.Println(s) // {5}
}
and why am I not using any &?
Pointer method receiver is quite special, it can also be called from non-pointer struct object. Both of s.changeVal2(4) and (&s).changeVal2(5) are valid & will affect the value of someVar.
Example http://play.golang.org/p/sxCnCD2D6d
You have to use a pointer for the receiver - (summaries *InvoiceSummaries) - because otherwise the argument is passed by value, having a pointer means you pass a reference to the value instead. If not for that, then you couldn't modify the collection at all.
Inside of the methods body you have use * because it is the dereferncing operator and returns the value at the address. Ampersand (&) is the opposite, it gives the address of a value.
Nothing wrong with your code but normally addresses to slices aren't used. A slice is a small struct that gophers are normally happy to pass by value. If a method or function is creating a new slice, the gopher is happy to return the new slice, by value again, as the return value.
Of course passing a slice by value doesn't guarantee anything about the backing store remaining unchanged when the method/function returns. So it can't be used as a way of guaranteeing the data elements of the slice haven't mutated.
How could I get an output of struct, sorted by fields?
type T struct {
B int
A int
}
t := &T{B: 2, A: 1}
doSomething(t)
fmt.Println(t) // &{1 2} --> Sorted by fields
A struct is an ordered collection of fields. The fmt package uses reflection to get the fields and values of a struct value, and generates output in the order in which they were defined.
So the simplest solution would be to declare your type where you already have your fields arranged in alphabetical order:
type T struct {
A int
B int
}
If you can't modify the order of fields (e.g. memory layout is important), you can implement the Stringer interface by specifying a String() method for your struct type:
func (t T) String() string {
return fmt.Sprintf("{%d %d}", t.A, t.B)
}
The fmt package checks if the passed value implements Stringer, and if it does, calls its String() method to generate the output.
Cons of this solution is that this is not flexible (e.g. if you add a new field, you have to update the String() method too), also you have to do it for every struct type you want it to work (and you can't define methods for types defined in other packages).
The completely flexible solution can use reflection. You can get the names of fields, sort them by name, and then iterate over the sorted names and get the field values (by name).
Pros of this solution is that this works for any struct, and it keeps working without modification even if you add or remove fields from your structs. It also works for fields of any type, not just for int fields.
Here is an example how to do it (try it on the Go Playground):
func printFields(st interface{}) string {
t := reflect.TypeOf(st)
names := make([]string, t.NumField())
for i := range names {
names[i] = t.Field(i).Name
}
sort.Strings(names)
v := reflect.ValueOf(st)
buf := &bytes.Buffer{}
buf.WriteString("{")
for i, name := range names {
val := v.FieldByName(name)
if !val.CanInterface() {
continue
}
if i > 0 {
buf.WriteString(" ")
}
fmt.Fprintf(buf, "%v", val.Interface())
}
buf.WriteString("}")
return buf.String()
}
Make T implement the Stringer interface (see package fmt) and do either print A orb B first.
BTW. This is a stupid idea.