2014-04-13 11 views
13

को लपेटने वाले इंटरफ़ेस के फ़ील्ड सेट नहीं कर सकता है, मैं एक ऐसी विधि को लागू करने की कोशिश कर रहा हूं जो किसी ऑब्जेक्ट में फ़ील्ड के मान को बदलता है जिसमें मनमानी संरचना हो सकती है। जब मेरे पास संरचना में सूचक होता है तो फ़ील्ड का ट्रैवर्स कोई समस्या नहीं है। लेकिन मैं जब मैं एक अंतरफलक है कि एक struct लेकिन struct खुद के लिए सूचक लपेट नहीं है क्षेत्रों को बदलने के लिए, संक्षेप में प्रबंधन कर सकते हैं नहीं:गोलांग प्रतिबिंब: एक संरचना

// The following doesn't work 
var x interface{} = A{Str: "Hello"} 
// This panics: reflect: call of reflect.Value.Field on ptr Value 
reflect.ValueOf(&x).Field(0).SetString("Bye") 
// This panics: reflect: call of reflect.Value.Field on interface Value 
reflect.ValueOf(&x).Elem().Field(0).SetString("Bye") 
// This panics: reflect: reflect.Value.SetString using unaddressable value 
reflect.ValueOf(&x).Elem().Elem().Field(0).SetString("Bye") 
// This prints `false`. But I want this to be settable 
fmt.Println(reflect.ValueOf(&x).Elem().Elem().Field(0).CanSet()) 

// This works 
var z interface{} = &A{Str: "Hello"} 
// This prints `true` 
fmt.Println(reflect.ValueOf(z).Elem().Field(0).CanSet()) 

लंबे में: http://play.golang.org/p/OsnCPvOx8F

मैं The Laws of Reflection पढ़ लिया है इसलिए मुझे पता है कि जब मैं संरचना में सूचक हूं तो मैं केवल फ़ील्ड को संशोधित कर सकता हूं। तो मेरा सवाल अब है: मैं संरचना के डेटा पर पॉइंटर कैसे प्राप्त करूं?

अद्यतन:

मैं यह मूल रूप से का उपयोग कर कार्य y := reflect.New(reflect.TypeOf(x)) तो y के मूल्यों अब settable हैं मिला है। एक व्यापक उदाहरण के लिए यह देखें: https://gist.github.com/hvoecking/10772475

उत्तर

8

आप एक इंटरफ़ेस चर के अंदर संग्रहीत गतिशील मान को संशोधित करने का प्रयास कर रहे हैं। इंटरफ़ेस वैरिएबल पर आप जो एकमात्र ऑपरेशन कर सकते हैं वह गतिशील मान (प्रतिलिपि बनाने वाले ऑपरेशन) को प्राप्त या सेट करना है, और संग्रहीत मूल्य के प्रकार की जांच करना है।

को समझने के लिए क्यों बातें इस तरह से कर रहे हैं, कल्पना ऐसे ऑपरेशन था और हम निम्न कोड था:

var ptr *A = pointer_to_dynamic_value(x) 
x = B{...} 

क्या ptr अब दर्शाता है? भाषा जब एक अंतरफलक चर करने के लिए नए मान निर्दिष्ट भंडारण का पुन: उपयोग करने के लिए स्वतंत्र है, इसलिए ptr अब B मूल्य है, जो प्रकार (वर्तमान compilers भंडारण के साथ भाषा की सुरक्षा टूट जाता है केवल होने की गारंटी है के लिए स्मृति को इंगित कर सकता छोटे मूल्यों के लिए पुन: उपयोग किया गया, लेकिन बिंदु बनी हुई है)।

इंटरफ़ेस में संग्रहीत मूल्य को म्यूटेट करने का एकमात्र सुरक्षित तरीका मान को कॉपी करना है, फिर संशोधित संस्करण को असाइन करना है। उदाहरण के लिए:

a := x.(A) 
a.Str = "Bye" 
x = a 

reflect पैकेज इन प्रतिबंधों को दर्शाता है, इसलिए reflect.Value गतिशील मान के क्षेत्र का प्रतिनिधित्व करने वाले केवल पढ़ने के लिए माना जाता है।

आप अपने पहले उदाहरण में फ़ील्ड सेट करने में सक्षम हैं क्योंकि z के लिए गतिशील मान संरचना के बजाए *A पॉइंटर है: इसका मतलब है संदर्भित संरचना को संशोधित किया जा सकता है।

+1

आह, मुझे यह मिल गया। कि समस्या को हल मेरे तरीका होगा 'y की मदद से एक नया उदाहरण बनाने के लिए (क्रम मनमाना structs का समर्थन करने के लिए): = reflect.New (reflect.TypeOf (x))' और 'को x' के सभी क्षेत्रों कॉपी 'y' के संबंधित फ़ील्ड। – Heye

+0

धन्यवाद हे, आपने मुझे खोज का एक और घंटे बचाया। :) – Danyel

+0

यह सही समझ में आता है; लेकिन क्यों आप के लिए उदाहरण के एक गतिशील मान के अंदर एक क्षेत्र नहीं बदल सकते, के लिए तर्क क्या है "एक्स (सूची) .head = z।" - के बाद से यह एक झूलने सूचक नहीं बनाता है। – WPWoodJr

संबंधित मुद्दे