Go에서 구조체의 필드를 반복합니다.


107

기본적으로 a의 필드 값을 반복하는 유일한 방법 (내가 알고있는) struct은 다음과 같습니다.

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
}

을 달성하는 더 좋고 더 다양한 방법이 있는지 궁금합니다. []interface{}{ r.a_number, r.a_string, }그래서 각 매개 변수를 개별적으로 나열 할 필요가 없습니다. 아니면 구조체를 반복하는 더 좋은 방법이 있습니까?

reflect패키지 를 살펴 보려고했지만 벽에 부딪 혔습니다 reflect.ValueOf(*r).Field(0). 일단을 검색하면 어떻게해야할지 모르겠 기 때문 입니다.

감사!


5
다음은 리플렉션에 관한 매우 흥미로운 기사입니다. blog.golang.org/laws-of-reflection 기사 의 예 중 하나를 따르십시오 . play.golang.org/p/_bKAQ3dQlu 그러나 내 보내지 않은 필드는 조회 할 수 없습니다. reflect 패키지 사용 (즉, 소문자로 시작하는 필드)
creack

답변:


126

reflect.Value를 사용하여 필드를 검색 Field(i)한 후을 호출하여 인터페이스 값을 가져올 수 있습니다 Interface(). 그런 다음 상기 인터페이스 값은 필드의 값을 나타냅니다.

아시다시피 이동중인 제네릭이 없으므로 필드의 값을 구체적인 유형으로 변환하는 기능이 없습니다. 따라서 해당 필드의 유형 인 서명이 GetValue() T 있는 기능은 없습니다 T(물론 필드에 따라 변경됨).

이동 중에 달성 할 수있는 가장 가까운 GetValue() interface{}것은 바로 이것이 reflect.Value.Interface() 제공하는 것입니다.

다음 코드는 리플렉션 ( 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)
}

24
go는 제네릭이 필요하지 않기 때문입니다. 기침, 기침 :-) 필드의 유형을 얻을 수있는 방법이 있습니까?
U Avalos

1
를 통해 reflect.Value.Type()예. 그러나 유형은 이동중인 일류 시민이 아니므로 .NET을 사용하여 해당 유형의 새 값만 인스턴스화 할 수 있습니다 reflect.
니모

6
v.Field(i).Interface()내 보내지 않은 개인 필드에 액세스하려고하면 패닉이 발생합니다. 조심하세요 :)
Tarion

10
v.Field(i).CanInterface() 하나를 사용하면 내 보내지 않은 필드의 경우 패닉을 피할 수 있습니다.
Pedram Esmaeeli

1
필드 이름을 어떻게 얻을 수 있습니까?
Sathesh

33

구조체의 필드와 값을 반복하려면 아래 Go 코드를 참조로 사용할 수 있습니다.

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

놀이터 에서 실행

참고 : 구조체의 필드를 내 보내지 않으면 v.Field(i).Interface()패닉이 발생합니다.panic: reflect.Value.Interface: cannot return value obtained from unexported field or method.


0

Chetan Kumar 솔루션을 복용 하고 신청해야하는 경우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"))
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.