Go'da bir yapının alanları arasında yineleme


108

Temel olarak, a'nın alanlarının değerlerini yinelemenin (bildiğim) tek yolu structşudur:

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
}

Merak ediyordum, başarmanın daha iyi ve daha çok yönlü bir yolu var mı []interface{}{ r.a_number, r.a_string, }, bu yüzden her parametreyi ayrı ayrı listelememe gerek yok, yoksa alternatif olarak, bir yapı boyunca döngü yapmanın daha iyi bir yolu var mı?

reflectPaketi incelemeye çalıştım ama duvara çarptım, çünkü aldığım zaman ne yapacağımı bilmiyorum reflect.ValueOf(*r).Field(0).

Teşekkürler!


5
İşte yansıma ile ilgili çok ilginç bir makale: blog.golang.org/laws-of-reflection Makaledeki örnekten birini takip ederek: play.golang.org/p/_bKAQ3dQlu Ancak, dışa aktarılmamış alanları arayamayacağınızı unutmayın yansıtma paketi ile (yani küçük harfle başlayan alanlar)
creack

Yanıtlar:


126

reflect.ValueKullanarak alanı aldıktan sonra Field(i)arayarak ondan bir arayüz değeri alabilirsiniz Interface(). Söz konusu arayüz değeri daha sonra alanın değerini temsil eder.

Alanın değerini somut bir türe dönüştürmenin bir işlevi yoktur, bildiğiniz gibi, harekette jenerik yoktur. Bu durumda, imza ile hiçbir işlevi yoktur GetValue() T ile T(alanına bağlı olarak, tabii ki değişiklikler) bu alan tipi olmak.

Hareket halindeyken elde edebileceğiniz en yakın şey GetValue() interface{}ve bu tam olarak reflect.Value.Interface() sunulan şeydir .

Aşağıdaki kod, yansıma ( oyun ) kullanarak bir yapıdaki dışa aktarılan her alanın değerlerinin nasıl alınacağını gösterir :

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
Evet, çünkü go'nun jeneriklere ihtiyacı yok. Öksürük, öksürük :-) Tarlanın türünü anlamanın bir yolu var mı?
U Avalos

1
yoluyla reflect.Value.Type(), evet. Ancak, türlerin birinci sınıf vatandaşlar olmadığını unutmayın, bu nedenle yalnızca bu türden yeni değerleri kullanarak somutlaştırabilirsiniz reflect.
nemo

7
v.Field(i).Interface()Dışa aktarılmamış özel alanlara erişmeye çalışırsanız paniğe kapılır. Dikkatli ol :)
Tarion

11
v.Field(i).CanInterface() Dışa aktarılmayan alanlar durumunda birini kullanmak paniği önleyebilir.
Pedram Esmaeeli

1
Alan adını nasıl alabilirim?
Sathesh

33

Bir yapının Alanlarını ve Değerlerini yinelemek istiyorsanız, aşağıdaki Go kodunu referans olarak kullanabilirsiniz.

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

Oyun alanında koş

Not: Yapınızdaki Alanlar dışa aktarılmazsa v.Field(i).Interface()panik yaratır.panic: reflect.Value.Interface: cannot return value obtained from unexported field or method.


0

Alarak Chetan Kumar çözümü ve durumda a uygulamak gerekirmap[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"))
}


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.