गो में एक संरचना के क्षेत्रों के माध्यम से Iterate


107

मूल रूप से, एक ही रास्ता (कि मुझे पता है) एक के क्षेत्रों के मूल्यों के माध्यम से पुनरावृति 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
हाँ, क्योंकि जाने के लिए जेनरिक की ज़रूरत नहीं है। खांसी, खांसी :-) क्या क्षेत्र का प्रकार प्राप्त करने का एक तरीका है?
यू अवलोस

1
के माध्यम से reflect.Value.Type(), हाँ। लेकिन ध्यान दें कि प्रकार प्रथम श्रेणी के नागरिक नहीं हैं, इसलिए आप केवल उस प्रकार के नए मूल्यों का उपयोग कर सकते हैं reflect
nemo

6
v.Field(i).Interface()यदि आप गैर-निर्यात किए गए निजी क्षेत्रों तक पहुँचने का प्रयास करते हैं तो पैनिक। बस सावधान रहें :)
टेरियन

10
v.Field(i).CanInterface() एक का उपयोग करने से अनएक्सपोर्टेड फ़ील्ड के मामले में घबराहट से बचा जा सकता है।
पेद्राम एस्माईली

1
मुझे फ़ील्ड नाम कैसे मिल सकता है?
षष्ठेश

33

यदि आप किसी संरचना के क्षेत्र और मान के माध्यम से Iterate करना चाहते हैं तो आप संदर्भ के रूप में नीचे दिए गए गो कोड का उपयोग कर सकते हैं।

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 Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.