2013-02-26 229 views
19

मैं वर्तमान में गो भाषा के साथ प्रोग्राम करना सीख रहा हूं। मुझे गो पॉइंटर्स को समझने में कुछ कठिनाइयों का सामना करना पड़ रहा है (और मेरा सी/सी ++ अब बहुत दूर है ...)। जाओ # 52 (http://tour.golang.org/#52) उदाहरण के लिए की यात्रा में, मैं पढ़ें:गोलांग पॉइंटर्स

type Vertex struct { 
    X, Y float64 
} 

func (v *Vertex) Abs() float64 { 
    return math.Sqrt(v.X*v.X + v.Y*v.Y) 
} 

func main() { 
    v := &Vertex{3, 4} 
    fmt.Println(v.Abs()) 
} 

लेकिन अगर बजाय

मैं ने लिखा है:

func (v Vertex) Abs() float64 { 
[...] 
v := Vertex{3, 4} 

या भी:

func (v Vertex) Abs() float64 { 
[...] 
v := &Vertex{3, 4} 

और इसके विपरीत:

func (v *Vertex) Abs() float64 { 
[...] 
v := Vertex{3, 4} 

मुझे एक ही परिणाम मिला। क्या कोई अंतर है (स्मृति-वार, आदि)?

+2

हैलो और प्रोग्रामर में आपका स्वागत है। इन जैसे प्रत्यक्ष कार्यान्वयन प्रश्न यहां ऑफ-विषय हैं लेकिन स्टैक ओवरफ़्लो पर विषय पर हैं। मैं माइग्रेट शुरू करूंगा। आप का दिन सुखद रहे। –

+2

सभी विधियों में 'v' को म्यूट करने का प्रयास करें, और उसके बाद' fmt.Println() 'कॉल के बाद मूल, और आप अंतर देखेंगे। '(V Vertex) 'संस्करणों के साथ, आपको मूल की प्रति प्राप्त हो रही है। अगर इसे पॉइंटर पर बुलाया गया था, तो यह आपके लिए स्वचालित रूप से अस्वीकृत है। –

+1

यह भी देखें: [विधि रिसीवर अस्पष्टता] (http://stackoverflow.com/questions/14926860/method-receivers-ambiguity) –

उत्तर

31

आपके उदाहरण के द्वारा प्रयोग किया जाने भाषा के दो विभिन्न नियम हैं:

  1. यह एक मूल्य के रिसीवर के साथ एक विधि से एक सूचक रिसीवर के साथ एक विधि प्राप्त करने के लिए संभव है। इस प्रकार func (v Vertex) Abs() float64 स्वचालित रूप से एक अतिरिक्त विधि कार्यान्वयन उत्पन्न करेगा:

    func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X+v.Y*v.Y) } 
    func (v *Vertex) Abs() float64 { return Vertex.Abs(*v) } // GENERATED METHOD 
    

    संकलक स्वचालित रूप से उत्पन्न विधि मिलेगा:

    v := &Vertex{3, 4} 
    v.Abs() // calls the generated method 
    
  2. जाओ स्वचालित रूप से एक चर के पते ले सकते हैं।निम्न उदाहरण में:

    func (v *Vertex) Abs() float64 { return math.Sqrt(v.X*v.X+v.Y*v.Y) } 
    func main() { 
        v := Vertex{3, 4} 
        v.Abs() 
    } 
    

    अभिव्यक्ति v.Abs() निम्न कोड के बराबर है:

    func (v *Vertex) Abs().... 
    

    रिसीवर:

    vp := &v 
    vp.Abs() 
    
+0

क्या कर रहा है * v स्मृति में v की प्रतिलिपि बनाता है (Vertex संरचना)? यदि नहीं, तो func (v Vertex) Abs() के निष्पादन के दौरान v में स्वयं परिवर्तन को बाहर दर्शाता है? – MaX

+2

'func (v Vertex) Abs() 'दर्ज करने से पहले संरचना Vertex की एक नई प्रति बनाई गई है। –

+1

@Atom पहले मामले में लिखने के लिए और अधिक सही नहीं है, जब स्ट्रक्चर वर्टेक्स को 'func (v Vertex) Abs() ':' func (v * Vertex) Abs() float64 {return (* v) .एबीएस()} // सामान्य विधि '? मुझे Vertex.Abs (* v) समझने में समस्याएं आ रही हैं ... – eAbi

2

अंतर पास-दर-मान बनाम पास-बाय-रेफरेंस है।

func f(v Vertex) में तर्क पैरामीटर पैरामीटर पर प्रतिलिपि है। func f(v *Vertex) में मौजूदा Vertex उदाहरण के लिए एक पॉइंटर पास हो गया है।

विधियों का उपयोग करते समय, कुछ डेरफ़्रेंसिंग आपके लिए किया जा सकता है, इसलिए आपके पास func (v *Vertex) f() विधि हो सकती है और पहले पॉइंटर लेने के बिना इसे कॉल करें: v := Vertex{...}; v.f()। यह सिंटैक्स चीनी, AFAIK का सिर्फ एक अनाज है।

13

अंतर हैं। उदाहरण के लिए, गैर-सूचक प्राप्तकर्ता प्रपत्र एक प्रतिलिपि पर काम करने के लिए विधि को मजबूर करता है। इस तरह से विधि उस आवृत्ति को म्यूट करने में सक्षम नहीं है जिस पर इसे लागू किया गया था - यह केवल प्रतिलिपि तक पहुंच सकता है। जो कि उदाहरण के मामले में अप्रभावी हो सकता है समय/स्मृति प्रदर्शन/खपत इत्यादि

ओटीओएच, पॉइंटर रिसीवर के साथ उदाहरण और विधियों के सूचक और जहां वांछित आसान उदाहरण साझाकरण (और उत्परिवर्तन) की अनुमति देता है।

अधिक जानकारी here

0

उन उदाहरण में दो मुख्य मतभेद रहे हैं v के लिए पास-दर-संदर्भ होगा और आप करेंगे संकेत पर केवल इस विधि कॉल करने में सक्षम हो:

v := Vertex{1,3} 
v.Abs() // This will result in compile time error 
&v.Abs() // But this will work 

दूसरी ओर

func (v Vertex) Abs() .... 

आप दोनों संकेत और structs पर इस विधि कॉल कर सकते हैं। जब आप इस विधि को पॉइंटर्स पर कॉल करते हैं तो भी रिसीवर पास-बाय-वैल्यू होगा।

v := Vertex{1,3} 
v.Abs() // This will work, v will be copied. 
&v.Abs() // This will also work, v will also be copied. 

आप func (v *Vertex) और func (v Vertex) दोनों घोषणा कर सकते हैं।

0

विनिर्देश के रूप में कहते हैं

एक विधि कॉल x.m() मान्य है (के प्रकार) की विधि सेट एक्स मीटर शामिल है और तर्क सूची मीटर की पैरामीटर सूची को सौंपा जा सकता है। यदि x पता है और & एक्स की विधि सेट मीटर, XM() के लिए (& एक्स) आशुलिपि मीटर() है शामिल हैं:

अपने मामले v.Abs में() & v.Abs के लिए आशुलिपि है() अगर विधि पता योग्य है।