मैं गो ऑब्जेक्ट के पॉइंटर वैल्यू को कैसे प्रिंट करूं? पॉइंटर वैल्यू का क्या मतलब है?


83

मैं बस गो के साथ खेल रहा हूं और अभी तक एक अच्छा मानसिक मॉडल नहीं है जब मूल्य या संदर्भ द्वारा संरचनाएं पारित की जाती हैं।

यह एक बहुत ही विनम्र प्रश्न हो सकता है लेकिन मैं बस थोड़ा प्रयोग करना चाहता हूं और देखना चाहता हूं कि क्या मैं अभी भी उसी वस्तु पर काम कर रहा हूं या मैंने इसकी एक प्रति बनाई है (इसे मूल्य द्वारा पारित किया है)।

क्या किसी वस्तु के पॉइंटर (या आंतरिक आईडी को प्रिंट करने का कोई तरीका है, तो पॉइंटर का मूल्य gc द्वारा बदल दिया जाता है)?

package main

import ( "runtime" )

type Something struct {
    number int
    queue chan int
}

func gotest( s *Something, done chan bool ) {
    println( "from gotest:")
    println( &s )
    for num := range s.queue {
        println( num )
        s.number = num
    }
    done <- true
}

func main() {
    runtime.GOMAXPROCS(4)
    s := new(Something)
    println(&s)
    s.queue = make(chan int)
    done := make(chan bool)
    go gotest(s, done)
    s.queue <- 42
    close(s.queue)
    <- done
    println(&s)
    println(s.number)
}

मेरी खिड़कियों पर देता है (8g संकलित संस्करण):

0x4930d4
from gotest:
0x4974d8
42
0x4930d4
42

गो रुटीन के भीतर से पॉइंटर का मान भिन्न मान क्यों दिखाता है? मूल वस्तु पर मात्रा बदल गई है इसलिए यह उसी वस्तु के साथ काम कर रहा है। क्या ऑब्जेक्ट आईडी देखने का कोई तरीका है जो लगातार है?

जवाबों:


114

फ़ंक्शन फ़ंक्शन तर्क मान द्वारा पास किए जाते हैं।

पहले, आइए अपने उदाहरण के अप्रासंगिक भागों को छोड़ दें, ताकि हम आसानी से देख सकें कि आप केवल मूल्य के आधार पर एक तर्क दे रहे हैं। उदाहरण के लिए,

package main

import "fmt"

func byval(q *int) {
    fmt.Printf("3. byval -- q %T: &q=%p q=&i=%p  *q=i=%v\n", q, &q, q, *q)
    *q = 4143
    fmt.Printf("4. byval -- q %T: &q=%p q=&i=%p  *q=i=%v\n", q, &q, q, *q)
    q = nil
}

func main() {
    i := int(42)
    fmt.Printf("1. main  -- i  %T: &i=%p i=%v\n", i, &i, i)
    p := &i
    fmt.Printf("2. main  -- p %T: &p=%p p=&i=%p  *p=i=%v\n", p, &p, p, *p)
    byval(p)
    fmt.Printf("5. main  -- p %T: &p=%p p=&i=%p  *p=i=%v\n", p, &p, p, *p)
    fmt.Printf("6. main  -- i  %T: &i=%p i=%v\n", i, &i, i)
}

आउटपुट:

1. main  -- i  int: &i=0xf840000040 i=42
2. main  -- p *int: &p=0xf8400000f0 p=&i=0xf840000040  *p=i=42
3. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040  *q=i=42
4. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040  *q=i=4143
5. main  -- p *int: &p=0xf8400000f0 p=&i=0xf840000040  *p=i=4143
6. main  -- i  int: &i=0xf840000040 i=4143

समारोह में main, iएक है intस्मृति स्थान पर चर ( &i) 0xf800000040एक प्रारंभिक मूल्य के साथ ( i) 42

समारोह में main, pएक के लिए सूचक है intस्मृति स्थान (कम से चर &p) 0xf8000000f0एक मूल्य (साथ p= &i) 0xf800000040एक करने के लिए जो अंक intमूल्य ( *p= i) 42

समारोह में main, byval(p)एक समारोह कॉल जो मूल्य (प्रदान करती है p= &i) 0xf800000040स्मृति स्थान (कम से तर्क के &p) 0xf8000000f0कार्य करने के लिए byvalपैरामीटर qस्मृति स्थान पर ( &q) 0xf8000000d8। दूसरे शब्दों में, मेमोरी को byvalपैरामीटर के लिए आवंटित किया जाता है qऔर main byvalतर्क pका मान इसे सौंपा जाता है; के मूल्यों pऔर qशुरू में ही कर रहे हैं, लेकिन चर pऔर qअलग हैं।

समारोह में byval, सूचक का उपयोग कर q( *int) है, जो सूचक की एक प्रति है p( *int), पूर्णांक *q( i) एक नई पूर्णांक मान पर सेट है 4143। लौटने से पहले अंत में। पॉइंटर qको nil(शून्य मान) पर सेट किया गया है , जिसका कोई प्रभाव नहीं है pक्योंकि qयह एक कॉपी है।

फ़ंक्शन में main, स्मृति स्थान पर pएक intचर के लिए एक संकेतक है ( &p) 0xf8000000f0एक मूल्य ( p= &i) के साथ 0xf800000040जो एक नए intमूल्य ( *p= i) को इंगित करता है 4143

फ़ंक्शन में main, एक अंतिम मान ( ) के साथ स्मृति स्थान ( ) पर iएक intचर है ।&i0xf800000040i4143

आपके उदाहरण में, फ़ंक्शन कॉल के तर्क के रूप में उपयोग किया जाने वाला फ़ंक्शन mainचर फ़ंक्शन पैरामीटर के समान नहीं है । उनके पास एक ही नाम है, लेकिन विभिन्न स्कोप और मेमोरी स्थानों के साथ अलग-अलग चर हैं। फ़ंक्शन पैरामीटर फ़ंक्शन कॉल तर्क को छुपाता है । यही कारण है कि मेरी उदाहरण में, मैं तर्क और पैरामीटर चर नामित है और क्रमश: अंतर पर जोर देना।sgotestgotestssspq

आपके उदाहरण में, ( &s) फ़ंक्शन में 0x4930d4चर के लिए मेमोरी स्थान का पता है जो फ़ंक्शन कॉल के तर्क के रूप में उपयोग किया जाता है , और फ़ंक्शन पैरामीटर के लिए मेमोरी स्थान का पता है । यदि आप फ़ंक्शन के अंत में पैरामीटर सेट करते हैं , तो इसका वेरिएबल पर कोई प्रभाव नहीं पड़ता है ; में और में विशिष्ट स्मृति स्थान नहीं है। प्रकारों के संदर्भ में, है , है , और है । एक पॉइंटर टू (मैमोरी लोकेशन का पता) है , जो कि पाइंटर टू (मेमोरी लोकेशन का पता) एक गुमनाम वैरायटी का प्रकार हैsmaingotest(s, done)0x4974d8gotestss = nilgotestsmainsmainsgotest&s**Somethings*Something*sSomething&ssSomething। मूल्यों के संदर्भ में, main.&s != gotest.&s, main.s == gotest.s, main.*s == gotest.*s, और main.s.number == gotest.s.number

आपको mkb की ऋषि सलाह लेनी चाहिए और इसका उपयोग बंद कर देना चाहिए println(&s)fmtउदाहरण के लिए पैकेज का उपयोग करें ,

fmt.Printf("%v %p %v\n", &s, s, *s)

जब वे एक ही मेमोरी लोकेशन की ओर इशारा करते हैं तो पॉइंटर्स का एक ही मूल्य होता है; जब वे अलग-अलग मेमोरी स्थानों पर इंगित करते हैं तो पॉइंटर्स के अलग-अलग मूल्य होते हैं।


मेरे उदाहरण में गेटएस्ट 'समथिंग' के लिए एक पॉइंटर लेता है, इसलिए मैं इसे उसी वस्तु के संदर्भ में मान रहा हूं और यह स्पष्ट रूप से तब होता है जब मैं गो-रुटीन के अंदर मूल्य बदल देता हूं, वस्तु का मुख्य फ़ंक्शन में भी इसका मान बदल जाता है । छपे हुए पॉइंटर का मान अलग है।
जेरेन डिर्क्स

@JamesDean आपके उदाहरण में, आप पॉइंटर मान और s प्रकार ** कुछ छपवा रहे हैं, जो कि पॉइंटर मान s टाइप * कुछ के समान नहीं है। मैंने मूल्य द्वारा सूचक को पास करने के लिए अपने उदाहरण को संशोधित किया है।
पेट्रोएस

@ जेम्स डीन आपने पॉइंटर (यानी पॉइंटर टू द sपॉइंटर) का पता छाप दिया, - पॉइंटर्स को वैल्यू द्वारा पास किया जाता है, का एड्रेस sवैसा नहीं है s। यदि आपके गोटे फंक्शन ने इंटेड किया है println( s ), तो वह पॉइंटर वैल्यू प्रिंट करेगा।
nos

ओह अब मैं देखता हूं कि क्या चल रहा है। Println (& s) करके मैं पॉइंटर वैल्यू के बजाय पॉइंटर का एड्रेस प्रिंट कर रहा था। अगर मैंने प्रिंट्लन (ओं) को किया होता तो इसमें मुख्य और गो रुटीन फंक्शन में एक ही पॉइंटर होता।
जीरन डिर्क

@JamesDean बिल्कुल। सी के रूप में गो में, s * समथिंग के लिए, & s, s और * s के बीच अंतर जानना आवश्यक है।
पेट्रो

6

गो में, तर्क मूल्य द्वारा पारित किए जाते हैं।

package main

import "fmt"

type SomeStruct struct {
    e int
}

// struct passed by value
func v(v SomeStruct) {
    fmt.Printf("v: %p %v\n", &v, v)
    v.e = 2
    fmt.Printf("v: %p %v\n", &v, v)
}

// pointer to struct passed by value
func p(p *SomeStruct) {
    fmt.Printf("p: %p %v\n", p, *p)
    p.e = 2
    fmt.Printf("p: %p %v\n", p, *p)
}

func main() {
    var s SomeStruct
    s.e = 1
    fmt.Printf("s: %p %v\n", &s, s)
    v(s)
    fmt.Printf("s: %p %v\n", &s, s)
    p(&s)
    fmt.Printf("s: %p %v\n", &s, s)
}

आउटपुट:

s: 0xf800000040 {1}
v: 0xf8000000e0 {1}
v: 0xf8000000e0 {2}
s: 0xf800000040 {1}
p: 0xf800000040 {1}
p: 0xf800000040 {2}
s: 0xf800000040 {2}


2

मैं गो ऑब्जेक्ट के पॉइंटर वैल्यू को कैसे प्रिंट करूं ?

package main

import (
    "fmt"
)

func main() {
    a := 42
    fmt.Println(&a)
}

का परिणाम:

0x1040a124

पॉइंटर वैल्यू का क्या मतलब है?

विकिपीडिया के अनुसार :

एक सूचक स्मृति में एक स्थान का संदर्भ देता है


1
package main

import "fmt"

func zeroval(ival int) {
     ival = 0
}

func zeroptr(iptr *int) {
     *iptr = 0
}

func main() {
    i := 1
    fmt.Println("initial:", i)
    zeroval(i)
    fmt.Println("zeroval:", i)
    //The &i syntax gives the memory address of i, i.e. a pointer to i.
    zeroptr(&i)
    fmt.Println("zeroptr:", i)
    //Pointers can be printed too.
    fmt.Println("pointer:", &i)
}

उत्पादन:

$ go run pointers.go
initial: 1
zeroval: 1
zeroptr: 0
pointer: 0x42131100
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.