प्रतिबिंबित का उपयोग करते हुए, आप एक संरचनात्मक क्षेत्र का मूल्य कैसे निर्धारित करते हैं?


106

reflectपैकेज का उपयोग करते हुए संरचना क्षेत्रों के साथ काम करने का एक कठिन समय है । विशेष रूप से, यह नहीं पता लगाया है कि फ़ील्ड मान कैसे सेट करें।

टाइप टी स्ट्रक्चर {फाई इंट; fs स्ट्रिंग}
var rt = t {123, "jblow"}
var i64 int64 = 456
  1. क्षेत्र का नाम प्राप्त करना - यह काम करने लगता है

    var field = reflect.TypeOf(r).Field(i).Name

  2. फ़ील्ड का मान प्राप्त करना एक) इंटरफ़ेस {}, बी) इंट - यह काम करने लगता है

    var iface interface{} = reflect.ValueOf(r).Field(i).Interface()

    var i int = int(reflect.ValueOf(r).Field(i).Int())

  3. फ़ील्ड i का मान सेट करना - एक प्रयास करें - आतंक

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    घबराहट : चिंतन.वैलू · सेटिफ़ाइड का उपयोग करते हुए प्राप्त किए गए मान का उपयोग करें

    यह मानते हुए कि यह "नाम" और "नाम" फ़ील्ड नामों को पसंद नहीं करता था, इसलिए इसका नाम बदलकर "आईडी" और "नाम" रखा गया।

    a) क्या यह धारणा सही है?

    ख) यदि सही है, तो उसी फ़ाइल / पैकेज में आवश्यक नहीं है

  4. फ़ील्ड i का मान सेट करना - दो को आज़माएं (फ़ील्ड के नाम बड़े अक्षरों में) - घबराहट

    reflect.ValueOf(r).Field(i).SetInt( 465 )

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    घबराहट : चिंतन.वैलू · अनअपेक्षित मान का उपयोग कर सेट करें


@PeterSO द्वारा नीचे दिए गए निर्देश पूरी तरह से और उच्च गुणवत्ता वाले हैं

चार। यह काम:

reflect.ValueOf(&r).Elem().Field(i).SetInt( i64 )

उन्होंने दस्तावेजों के साथ ही कहा कि क्षेत्र के नाम निर्यात योग्य होने चाहिए (पूंजी पत्र के साथ शुरू)


निकटतम उदाहरण मैं का उपयोग कर किसी के लिए मिल सकता है reflectसेट डेटा के लिए गया था comments.gmane.org/gmane.comp.lang.go.general/35045 , लेकिन फिर भी वहाँ वह इस्तेमाल किया json.Unmarshalवास्तविक गंदा काम करने के लिए
सीसी युवा

(उपरोक्त टिप्पणी अप्रचलित है)
cc युवा

जवाबों:


156

गो ओपन सोर्स कोड के रूप में उपलब्ध है । प्रतिबिंब के बारे में जानने का एक अच्छा तरीका यह है कि कोर गो डेवलपर्स इसका उपयोग कैसे करें। उदाहरण के लिए, गो fmt और json संकुल। पैकेज प्रलेखन में हेडिंग पैकेज फ़ाइलों के अंतर्गत स्रोत कोड फ़ाइलों के लिंक होते हैं।

गो जसन पैकेज मार्शल्स और अनमरशल्स JSON से और गो संरचनाओं में।


यहां एक चरण-दर-चरण उदाहरण दिया गया है जो structत्रुटियों से बचने के साथ-साथ एक फ़ील्ड का मान सेट करता है ।

गो reflectपैकेज में एक CanAddrफंक्शन होता है।

func (v Value) CanAddr() bool

यदि Addr के साथ मान का पता प्राप्त किया जा सकता है, तो CanAddr सही है। ऐसे मूल्यों को संबोधन कहा जाता है। एक मान पता योग्य है यदि यह एक स्लाइस का एक तत्व है, एक पता योग्य सरणी का एक तत्व है, एक पता योग्य संरचना का एक क्षेत्र है, या एक पॉइंटर को डेरेफेर करने का परिणाम है। यदि CanAddr गलत है, तो Addr को कॉल करने से घबराहट होगी।

गो reflectपैकेज में एक CanSetफ़ंक्शन होता है, जो, यदि true, इसका अर्थ CanAddrभी है true

func (v Value) CanSet() bool

यदि v का मान बदला जा सकता है तो कैनसेट सही है। एक मान केवल तभी बदला जा सकता है जब यह पता योग्य हो और गैर-पंजीकृत संरचना क्षेत्रों के उपयोग द्वारा प्राप्त नहीं किया गया हो। यदि कैनसेट गलत है, तो सेट या किसी भी प्रकार के विशिष्ट सेटर (जैसे, सेटबूल, सेटआईंट 64) से घबराहट होगी।

हमें यकीन है कि हम कर सकते हैं बनाने की जरूरत है क्षेत्र। उदाहरण के लिए,Setstruct

package main

import (
    "fmt"
    "reflect"
)

func main() {
    type t struct {
        N int
    }
    var n = t{42}
    // N at start
    fmt.Println(n.N)
    // pointer to struct - addressable
    ps := reflect.ValueOf(&n)
    // struct
    s := ps.Elem()
    if s.Kind() == reflect.Struct {
        // exported field
        f := s.FieldByName("N")
        if f.IsValid() {
            // A Value can be changed only if it is 
            // addressable and was not obtained by 
            // the use of unexported struct fields.
            if f.CanSet() {
                // change value of N
                if f.Kind() == reflect.Int {
                    x := int64(7)
                    if !f.OverflowInt(x) {
                        f.SetInt(x)
                    }
                }
            }
        }
    }
    // N at end
    fmt.Println(n.N)
}

Output:
42
7

यदि हम निश्चित हो सकते हैं कि सभी त्रुटि जांच अनावश्यक हैं, तो उदाहरण सरल हो जाता है,

package main

import (
    "fmt"
    "reflect"
)

func main() {
    type t struct {
        N int
    }
    var n = t{42}
    fmt.Println(n.N)
    reflect.ValueOf(&n).Elem().FieldByName("N").SetInt(7)
    fmt.Println(n.N)
}

5
छोड़ दो! वहाँ कहीं एक जवाब है, लेकिन json pkg पर चार घंटे के काम ने मुझे नहीं दिया है। पुनः दर्शाए गए pkg, जानकारी खींचना बहुत सरल है, लेकिन डेटा सेट करने के लिए कुछ काले जादू की आवश्यकता होती है, जिसके लिए मैं कहीं एक सरल उदाहरण देखना पसंद करूंगा!
cc युवा

2
बकाया! यदि आप कभी थाईलैंड में हैं तो कृपया मुझे एक बियर या दो या तीन के लिए इलाज करें! बहुत बहुत धन्यवाद
cc युवा

5
महान व्यावहारिक उदाहरण, इस लेख ने मेरे लिए इसे पूरी तरह से ध्वस्त कर दिया golang.org/doc/articles/laws_of_reflection.html
danmux

बहुत बढ़िया उदाहरण हैं। समान कोड play.golang.org/p/RK8jR_9rPh
सारथ

यह एक संरचनात्मक क्षेत्र सेट नहीं करता है। यह एक पॉइंटर में स्ट्रक्चर के लिए एक फील्ड सेट करता है। जाहिर है, यह ओपी द्वारा पूछे गए सवाल का जवाब नहीं है।
wvxvw

13

यह काम करने लगता है:

package main

import (
    "fmt"
    "reflect"
)

type Foo struct {
    Number int
    Text string
}

func main() {
    foo := Foo{123, "Hello"}

    fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))

    reflect.ValueOf(&foo).Elem().Field(0).SetInt(321)

    fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))
}

प्रिंटों:

123
321

धन्यवाद! अब जब मैंने peterSO के नोट्स पढ़ लिए हैं, तो यह सही समझ में आता है। मैं फू, नहीं और फू का उपयोग कर रहा था, इसलिए बदला नहीं जा सकता था, और अनिश्चित था कि एलम () क्या था।
cc युवा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.