2015-10-15 6 views
8

इस कोड:फ़ील्ड के स्ट्रिंग() के साथ स्ट्रक्चर प्रिंट कैसे करें?

type A struct { 
    t time.Time 
} 

func main() { 
    a := A{time.Now()} 
    fmt.Println(a) 
    fmt.Println(a.t) 
} 

प्रिंट:

{{63393490800 0 0x206da0}} 
2009-11-10 23:00:00 +0000 UTC 

AString() को लागू नहीं करता है, इसलिए यह एक fmt.Stringer नहीं है और इसके मूल प्रतिनिधित्व प्रिंट करता है। लेकिन मैं मुद्रित करना चाहता हूं प्रत्येक एकल संरचना के लिए String() लागू करने के लिए बहुत कठिन है। इससे भी बदतर, मुझे String() एस अपडेट करना होगा यदि मैं कुछ फ़ील्ड जोड़ता हूं या हटा देता हूं। क्या इसके क्षेत्र 'String() एस के साथ एक संरचना मुद्रित करने का कोई आसान तरीका है?

उत्तर

4

इस प्रकार fmt पैकेज लागू किया गया है, इसलिए आप इसे बदल नहीं सकते हैं।

लेकिन आप एक सहायक कार्य लिख सकते हैं जो एक संरचना के क्षेत्र में पुनरावृत्ति के लिए प्रतिबिंब (reflect पैकेज) का उपयोग करता है, और यदि उनके पास ऐसी विधि है तो String() फ़ील्ड पर विधि को कॉल कर सकते हैं।

उदाहरण कार्यान्वयन:

func PrintStruct(s interface{}, names bool) string { 
    v := reflect.ValueOf(s) 
    t := v.Type() 
    // To avoid panic if s is not a struct: 
    if t.Kind() != reflect.Struct { 
     return fmt.Sprint(s) 
    } 

    b := &bytes.Buffer{} 
    b.WriteString("{") 
    for i := 0; i < v.NumField(); i++ { 
     if i > 0 { 
      b.WriteString(" ") 
     } 
     v2 := v.Field(i) 
     if names { 
      b.WriteString(t.Field(i).Name) 
      b.WriteString(":") 
     } 
     if v2.CanInterface() { 
      if st, ok := v2.Interface().(fmt.Stringer); ok { 
       b.WriteString(st.String()) 
       continue 
      } 
     } 
     fmt.Fprint(b, v2) 
    } 
    b.WriteString("}") 
    return b.String() 
} 

अब जब आप एक struct प्रिंट करना चाहते हैं, तो आप कर सकते हैं:

fmt.Println(PrintStruct(a, true)) 

आप भी अपने struct करने के लिए एक String() विधि जोड़ने के लिए जो सिर्फ करने के लिए है चुन सकते हैं हमारे PrintStruct() फ़ंक्शन पर कॉल करें:

func (a A) String() string { 
    return PrintStruct(a, true) 
} 

जब भी आप अपनी संरचना बदलते हैं, तो आपको अपने String() विधि के साथ कुछ भी करने की ज़रूरत नहीं है क्योंकि यह सभी क्षेत्रों में गतिशील रूप से चलने के लिए प्रतिबिंब का उपयोग करता है।

नोट्स:

type A struct { 
    T   time.Time 
    I   int 
    unexported string 
} 

परीक्षण:

हम प्रतिबिंब का उपयोग कर रहे हैं, आप t time.Time क्षेत्र निर्यात करने के लिए यह काम करने के लिए है (यह भी परीक्षण प्रयोजनों के लिए कुछ अतिरिक्त क्षेत्रों जोड़ा) यह:

a := A{time.Now(), 2, "hi!"} 
fmt.Println(a) 
fmt.Println(PrintStruct(a, true)) 
fmt.Println(PrintStruct(a, false)) 
fmt.Println(PrintStruct("I'm not a struct", true)) 

आउटपुट (यह Go Playground पर कोशिश):

0,123,
{T:2009-11-10 23:00:00 +0000 UTC I:2 unexported:hi!} 
{T:2009-11-10 23:00:00 +0000 UTC I:2 unexported:hi!} 
{2009-11-10 23:00:00 +0000 UTC 2 hi!} 
I'm not a struct 
+0

वही है जो मैं टालने का प्रयास करता हूं। मैं अपने आंतरिक कार्यान्वयन को उजागर करने के बजाय 'time.ime' की 'स्ट्रिंग()' का उपयोग करना चाहता हूं। –

+0

@ लाईयू-ह्यूआन आप सही हैं। संपादित उत्तर देखें। – icza

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