Iterate through the fields of a struct in Go
Asked Answered
U

8

196

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!

Unlawful answered 20/9, 2013 at 21:39 Comment(1)
Here is a very interesting article regarding reflection: blog.golang.org/laws-of-reflection Following one of the example from the article: play.golang.org/p/_bKAQ3dQlu Note however that you can't lookup non-exported fields with the reflect package (i.e. fields that begins with lowercase)Lottery
V
188

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)
}
Velvetvelveteen answered 21/9, 2013 at 0:36 Comment(11)
Yea because go doesn't need generics. Cough, cough :-) Is there a way to get the type of the field?Ornie
via reflect.Value.Type(), yes. But note that types are not first-class citizens in go, so you can only instantiate new values of that type using reflect.Velvetvelveteen
v.Field(i).Interface() panics if you try to access non exported private fields. Just be careful :)Altitude
what if I want to check if the struct field is also a struct? when looping?@VelvetvelveteenBaldpate
@Baldpate see for example #42065726Velvetvelveteen
Using v.Field(i).CanInterface() one can avoid the panic in case of unexported fields.Fabrienne
How can I get the field name?Baneberry
In my case I needed the field name of the struct. The technique is very similar to the above answer except that reflect.TypeOf() is used instead of ValueOf(). Also the struct would need to have field tags associated to it. There is actually a field.Tag.Lookup("alias") method: golang.org/pkg/reflect/#StructTag . I also see a Get() method for the struct tag in the docs: golang.org/pkg/reflect/#StructTagWitkin
@Altitude Indeed gotta love incomplete answersThersathersites
@Thersathersites feel free to improve it.Velvetvelveteen
v.Field(i).Interface() seems to return a copy of the actual value. Is it possible to get the actual one? I'm trying dynamically get pointers to all the actual values of a struct fields using reflection.Repp
S
111

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.

Screen answered 17/7, 2019 at 10:12 Comment(0)
F
42

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(employeeDetails{}))
    for _, field := range fields {
        fmt.Printf("Key: %s\tType: %s\n", field.Name, field.Type)
    }
}
Forgiveness answered 6/3, 2021 at 22:35 Comment(1)
struct{ employeeDetails }{} can be replace with employeeDetails{}Bathilda
B
7

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)
Baptism answered 25/11, 2020 at 18:36 Comment(1)
Hi and welcome to Stack Overflow! Please take the tour. Thank for contributing an answer (age of the question doesn't matter). Can you explain a bit more how your answer solves the problem?Pentachlorophenol
N
0

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

Neese answered 11/5, 2021 at 1:21 Comment(0)
G
-1

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"))
}


Gush answered 24/1, 2020 at 11:5 Comment(0)
O
-1

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))
    }
}
Orlandoorlanta answered 27/4, 2021 at 3:54 Comment(0)
M
-2

In Go, you can use the reflect package to iterate through the fields of a struct. The reflect package allows you to inspect the properties of values at runtime, including their type and value. Here's an example of how to iterate through the fields of a struct:

Go Playground

package main

import (
    "fmt"
    "reflect"
)

type Movie struct {
    Name string
    Year int
}

func main() {
    p := Movie{"The Dark Knight", 2008}

    val := reflect.ValueOf(p)
    typ := val.Type()

    for i := 0; i < val.NumField(); i++ {
        field := val.Field(i)
        fieldType := typ.Field(i)

        fmt.Printf("Field Name: %s, Field Value: %v\n", fieldType.Name, field.Interface())
    }
}

Output:

Field Name: Name, Field Value: The Dark Knight
Field Name: Age, Field Value: 2008
Microtome answered 23/10, 2022 at 23:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.