Jak wydrukować wartość wskaźnika obiektu Go? Co oznacza wartość wskaźnika?

Po prostu bawię się z Go i nie mam jeszcze dobrego mentalnego modelu, kiedy struktury są przekazywane przez wartość lub przez odniesienie.

To może być bardzo głupie pytanie, ale po prostu chcę trochę poeksperymentować i zobaczyć, czy nadal pracuję nad tym samym obiektem, Czy zrobiłem jego kopię (przekazałem go przez wartość).

Czy istnieje sposób na wydrukowanie wskaźnika (lub wewnętrznego id, jeśli wartość wskaźnika została zmieniona przez gc) obiektu?

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)
}

Gives on my windows (8G skompilowany wersja):

0x4930d4
from gotest:
0x4974d8
42
0x4930d4
42

Dlaczego wartość wskaźnika z procedury go pokazuje inną wartość? Ilość na oryginalnym obiekcie została zmieniona, więc działał z tym samym obiektem. Czy istnieje sposób, aby zobaczyć identyfikator obiektu, który jest trwały?

 47
go
Author: Michael Myers, 2011-02-09

5 answers

Argumenty funkcji Go są przekazywane przez wartość.

Po pierwsze, odrzućmy nieistotne części twojego przykładu, abyśmy mogli łatwo zobaczyć, że po prostu przekazujesz argument przez wartość. Na przykład,

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)
}

Wyjście:

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

W funkcji main, i jest zmienną int W Miejscu Pamięci (&i) 0xf800000040 z wartością początkową (i) 42.

W funkcji main, p jest wskaźnikiem do zmiennej int W Miejscu Pamięci (&p) 0xf8000000f0 z wartość (p=&i) 0xf800000040 co wskazuje na wartość int(*p=i) 42.

W funkcji main, byval(p) jest wywołaniem funkcji, które przypisuje wartość (p=&i) 0xf800000040 argumentu w Miejscu Pamięci (&p) 0xf8000000f0 do funkcji byval parametru q w miejscu pamięci (&q) 0xf8000000d8. Innymi słowy, pamięć jest przydzielana dla parametru byval q i wartości main byval argument p jest przypisany do niego; wartości p i q są początkowo to samo, ale zmienne p i {[30] } są różne.

W funkcji byval, używając wskaźnika q (*int), który jest kopią wskaźnika p (*int), liczba całkowita *q (i) jest ustawiona na nową wartość int 4143. Na koniec przed powrotem. wskaźnik q jest ustawiony na nil (wartość zerowa), co nie ma wpływu na p, ponieważ q jest kopią.

W funkcji main, p jest wskaźnikiem do zmiennej int W Miejscu Pamięci (&p) 0xf8000000f0 z wartością (p=&i) {[7] } co wskazuje na nową wartość int (*p=i) 4143.

W funkcji main, i jest zmienną int W Miejscu Pamięci (&i) 0xf800000040 z wartością końcową (i) 4143.

W twoim przykładzie zmienna funkcji main s używana jako argument wywołania funkcji gotest nie jest taka sama jak parametr funkcji gotest s. Mają tę samą nazwę, ale są różnymi zmiennymi o różnych zakresach i lokalizacjach pamięci. Parametr funkcji s ukrywa argument wywołania funkcji s. Dlatego w moim przykładzie nazwałem zmienne argumentu i parametru p i q odpowiednio, aby podkreślić różnicę.

W twoim przykładzie, (&s) 0x4930d4 jest adresem lokalizacji pamięci zmiennej s w funkcji main, która jest używana jako argument wywołania funkcji gotest(s, done), A {[87] } jest adresem lokalizacji pamięci dla parametru funkcji gotest s. Jeśli ustawisz parametr s = nil na końcu funkcji gotest, nie ma wpływu na zmienną s W main; s w main i s w gotest są odrębnymi lokalizacjami pamięci. Pod względem typów &s jest **Something, s jest *Something i *s jest Something. &s jest wskaźnikiem do (adres lokalizacji pamięci) s, który jest wskaźnikiem do (adres lokalizacji pamięci) anonimowej zmiennej typu Something. Pod względem wartości, main.&s != gotest.&s, main.s == gotest.s, main.*s == gotest.*s, i main.s.number == gotest.s.number.

Powinieneś skorzystać z Rady mkb sage i przestać używać println(&s). Użyj fmt pakiet, na przykład,

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

Wskaźniki mają tę samą wartość, gdy wskazują na to samo miejsce pamięci; wskaźniki mają różne wartości, gdy wskazują na różne miejsca pamięci.

 62
Author: peterSO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-19 20:41:50

W Go argumenty są przekazywane przez wartość.

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)
}

Wyjście:

s: 0xf800000040 {1}
v: 0xf8000000e0 {1}
v: 0xf8000000e0 {2}
s: 0xf800000040 {1}
p: 0xf800000040 {1}
p: 0xf800000040 {2}
s: 0xf800000040 {2}
 5
Author: peterSO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-09 02:22:13
type sometype struct { }
a := sometype {}
b := int(2)
println("Ptr to a", &a)
println("Ptr to b", &b)
 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-08 21:55:03
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)
}

Wyjście:

$ go run pointers.go
initial: 1
zeroval: 1
zeroptr: 0
pointer: 0x42131100
 1
Author: Jetlum Ajeti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-10 20:55:29

Jak mogę wydrukować wartość wskaźnika obiektu Go?

package main

import (
    "fmt"
)

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

Wyniki w:

0x1040a124

Co oznacza wartość wskaźnika?

Według Wikipedii :

Wskaźnik odwołuje się do miejsca w pamięci

 0
Author: 030,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-17 13:23:12