Ітерація через поля структури в 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 Зауважте, що ви не можете шукати неекспортовані поля з пакетом відображення (тобто полями, що починаються з малих літер)
скрип

Відповіді:


126

Після того, як ви отримали reflect.Valueполе за допомогою, Field(i)ви можете отримати значення інтерфейсу від нього, зателефонувавши Interface(). Зазначене значення інтерфейсу потім представляє значення поля.

Немає функції перетворювати значення поля в конкретний тип, оскільки, як ви можете знати, жодних дженериків немає. Таким чином, немає функції з підписом GetValue() T з Tтипом цього поля (що змінюється, звичайно, залежно від поля).

Найближче, чого ви можете досягти, - GetValue() interface{}це саме те, що reflect.Value.Interface() пропонує.

Наступний код ілюструє, як отримати значення кожного експортованого поля в структурі за допомогою відображення ( відтворення ):

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
Так, тому що йти не потрібно дженериків. Кашель, кашель :-) Чи є спосіб отримати тип поля?
U Avalos

1
через reflect.Value.Type(), так. Але зауважте, що типи не є першокласними громадянами, тому ви можете лише створити нові значення цього типу, використовуючи reflect.
немо

6
v.Field(i).Interface()паніку, якщо ви намагаєтеся отримати доступ до приватних полів, які не експортуються. Тільки будьте уважні :)
Tarion

10
За допомогою v.Field(i).CanInterface() цього можна уникнути паніки у випадку неекспортованих полів.
Педрам Есмаелі

1
Як я можу отримати ім'я поля?
Сатеш

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

Беручи Четан Кумар рішення і в разі , якщо вам необхідно звернутися до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"))
}


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.