Iterate through the fields of a struct in Go

GoGo Reflect

Go Problem Overview


Basically, the only way (that I know of) to iterate through the values of the fields of a struct is like this:

type Example struct {
    a_number uint32
    a_string string
}

//...

r := &Example{(2 << 31) - 1, "...."}:
for _, d:= range []interface{}{ r.a_number, r.a_string, } {
  //do something with the d
}

I was wondering, if there's a better and more versatile way of achieving []interface{}{ r.a_number, r.a_string, }, so I don't need to list each parameter individually, or alternatively, is there a better way to loop through a struct?

I tried to look through the reflect package, but I hit a wall, because I'm not sure what to do once I retrieve reflect.ValueOf(*r).Field(0).

Thanks!

Go Solutions


Solution 1 - Go

After you've retrieved the reflect.Value of the field by using Field(i) you can get a interface value from it by calling Interface(). Said interface value then represents the value of the field.

There is no function to convert the value of the field to a concrete type as there are, as you may know, no generics in go. Thus, there is no function with the signature GetValue() T with T being the type of that field (which changes of course, depending on the field).

The closest you can achieve in go is GetValue() interface{} and this is exactly what reflect.Value.Interface() offers.

The following code illustrates how to get the values of each exported field in a struct using reflection (play):

import (
	"fmt"
	"reflect"
)

func main() {
	x := struct{Foo string; Bar int }{"foo", 2}

	v := reflect.ValueOf(x)

	values := make([]interface{}, v.NumField())

	for i := 0; i < v.NumField(); i++ {
		values[i] = v.Field(i).Interface()
	}

	fmt.Println(values)
}

Solution 2 - Go

If you want to Iterate through the Fields and Values of a struct then you can use the below Go code as a reference.

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Fname  string
    Lname  string
    City   string
    Mobile int64
}

func main() {
    s := Student{"Chetan", "Kumar", "Bangalore", 7777777777}
    v := reflect.ValueOf(s)
    typeOfS := v.Type()

    for i := 0; i< v.NumField(); i++ {
        fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Name, v.Field(i).Interface())
    }
}

Run in playground

Note: If the Fields in your struct are not exported then the v.Field(i).Interface() will give panic panic: reflect.Value.Interface: cannot return value obtained from unexported field or method.

Solution 3 - Go

Go 1.17 (Q3 2021) should add a new option, through commit 009bfea and CL 281233, fixing issue 42782.

> ## reflect: add VisibleFields function > > When writing code that reflects over a struct type, it's a common requirement to know the full set of struct fields, including fields available due to embedding of anonymous members while excluding fields that are erased because they're at the same level as another field with the same name. > > The logic to do this is not that complex, but it's a little subtle and easy to get wrong. > > This CL adds a new reflect.VisibleFields() function to the reflect package that returns the full set of effective fields that apply in a given struct type.

fields := reflect.VisibleFields(typ)
for j, field := range fields {
    ...
}

Example,

type employeeDetails struct {
    id          int16
    name        string
    designation string
}
func structIterator() {
	fields := reflect.VisibleFields(reflect.TypeOf(struct{ employeeDetails }{}))
	for _, field := range fields {
		fmt.Printf("Key: %s\tType: %s\n", field.Name, field.Type)
	}
}

Solution 4 - Go

Maybe too late :))) but there is another solution that you can find the key and value of structs and iterate over that

package main

import (
	"fmt"
	"reflect"
)

type person struct {
	firsName string
	lastName string
	iceCream []string
}

func main() {
	u := struct {
		myMap    map[int]int
		mySlice  []string
		myPerson person
	}{
		myMap:   map[int]int{1: 10, 2: 20},
		mySlice: []string{"red", "green"},
		myPerson: person{
			firsName: "Esmaeil",
			lastName: "Abedi",
			iceCream: []string{"Vanilla", "chocolate"},
		},
	}
	v := reflect.ValueOf(u)
	for i := 0; i < v.NumField(); i++ {
		fmt.Println(v.Type().Field(i).Name)
		fmt.Println("\t", v.Field(i))
	}
}
and there is no *panic* for v.Field(i)

Solution 5 - Go

use this:

type x struct {
	Id  int
	jsj int
}
func main() {
	x2 := x{jsj: 10, Id: 5}
	v := reflect.ValueOf(x2)
	for i := 0; i < v.NumField(); i++ {
		fmt.Println(v.Field(i))
	}
}

====>10

====>5

Solution 6 - Go

Taking Chetan Kumar solution and in case you need to apply to a map[string]int

package main

import (
	"fmt"
	"reflect"
)

type BaseStats struct {
	Hp           int
	HpMax        int
	Mp           int
	MpMax        int
	Strength     int
	Speed        int
	Intelligence int
}

type Stats struct {
	Base map[string]int
	Modifiers []string
}

func StatsCreate(stats BaseStats) Stats {
	s := Stats{
		Base: make(map[string]int),
	}

	//Iterate through the fields of a struct
	v := reflect.ValueOf(stats)
	typeOfS := v.Type()

	for i := 0; i< v.NumField(); i++ {
		val := v.Field(i).Interface().(int)
		s.Base[typeOfS.Field(i).Name] = val
	}
	return s
}

func (s Stats) GetBaseStat(id string) int {
	return s.Base[id]
}


func main() {
	m := StatsCreate(BaseStats{300, 300, 300, 300, 10, 10, 10})

	fmt.Println(m.GetBaseStat("Hp"))
}


Solution 7 - Go

Use reflect package. First, get the type of variable with reflect.TypeOf and get numbers of elements with reflect.NumField.To obtain the values of the fields iteratively of a structure must reflect the variable and use the function rg.Elem().Field(i)

package main

import (
	"fmt"
	"reflect"
)

type Gopher struct {
	Name  string
	Color string
	Year  int
}

func main() {
	g := Gopher{Name: "AAA", Color: "BBBB", Year: 2021}

	gtype := reflect.TypeOf(g)

	numFields := gtype.NumField()

	rg := reflect.ValueOf(&g)

	for i := 0; i < numFields; i++ {
		fmt.Println(rg.Elem().Field(i))
	}
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionomninonsenseView Question on Stackoverflow
Solution 1 - GonemoView Answer on Stackoverflow
Solution 2 - GoChetan KumarView Answer on Stackoverflow
Solution 3 - GoVonCView Answer on Stackoverflow
Solution 4 - GoEsmaeil AbediView Answer on Stackoverflow
Solution 5 - Gomahdi gadgetView Answer on Stackoverflow
Solution 6 - GoSTEELView Answer on Stackoverflow
Solution 7 - Gojamesev15View Answer on Stackoverflow