2011-02-08 20 views
43

Estoy jugando con Go y aún no tengo un buen modelo mental de cuándo se pasan las estructuras por valor o por referencia.¿Cómo imprimo el valor del puntero de un objeto Go? ¿Qué significa el valor del puntero?

Esto puede ser una pregunta muy tonta, pero solo quiero experimentar un poco y ver si todavía estoy trabajando en el mismo objeto o si he hecho una copia (lo pasó por valor).

¿Hay alguna manera de imprimir el puntero (o id interno si el valor del puntero es cambiado por gc) de un objeto?

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

da en mis ventanas (8g versión compilada):

0x4930d4 
from gotest: 
0x4974d8 
42 
0x4930d4 
42 

¿Por qué el valor del puntero dentro de la rutina de ir muestran un valor diferente? La cantidad en el objeto original cambió por lo que estaba trabajando con el mismo objeto. ¿Hay alguna forma de ver un identificador de objeto persistente?

Respuesta

51

argumentos de la función Go se pasan por valor.

Primero, descartemos las partes irrelevantes de su ejemplo, para que podamos ver fácilmente que simplemente está pasando un argumento por valor. Por ejemplo,

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

de salida:

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 

En función main, i es una variable int en la ubicación de memoria (&i) 0xf800000040 con un valor inicial (i) 42.

En función main, p es un puntero a una variable int en la ubicación de memoria (&p) 0xf8000000f0 con un valor (p = &i) 0xf800000040 que apunta a un valor int (*p = i) 42.

En función main, byval(p) es una llamada de función que asigna el valor (p = &i) 0xf800000040 del argumento en la ubicación de memoria (&p) 0xf8000000f0 al parámetro de función byvalq en la ubicación de memoria (&q) 0xf8000000d8. En otras palabras, la memoria se asigna para el byval parámetro q y se le asigna el valor del mainbyval argumento p; los valores de p y q son inicialmente los mismos, pero las variables p y son distintas.

En función byval, utilizando puntero q (*int), que es una copia de puntero p (*int), número entero *q (i) se ajusta a un nuevo valor int 4143. Al final antes de regresar. el puntero q se establece en nil (valor cero), que no tiene efecto en p ya que q es una copia.

En función main, p es un puntero a una variable int en la ubicación de memoria (&p) 0xf8000000f0 con un valor (p = &i) 0xf800000040 que apunta a un nuevo valor int (*p = i) 4143.

En función main, i es una variable int en la ubicación de memoria (&i) 0xf800000040 con un valor final (i) 4143.

En el ejemplo, la función main variables s utilizado como un argumento a la llamada de función gotest no es el mismo que el parámetro de la función gotests. Tienen el mismo nombre, pero son variables diferentes con diferentes ámbitos y ubicaciones de memoria. El parámetro de función s oculta el argumento de llamada de función s. Es por eso que en mi ejemplo, nombré las variables de argumento y parámetro p y q respectivamente para enfatizar la diferencia.

En su ejemplo, (&s) 0x4930d4 es la dirección de la posición de memoria para la variable s en función main que se utiliza como un argumento a la llamada a la función gotest(s, done) y 0x4974d8 es la dirección de la posición de memoria para la función gotest parámetro s. Si configura el parámetro s = nil al final de la función gotest, no tiene efecto en la variable s en main; s en main y s en gotest son ubicaciones distintas de memoria. En términos de tipos, &s es **Something, s es *Something, y *s es Something. &s es un puntero a (dirección de la ubicación de la memoria) s, que es un puntero a (dirección de la ubicación de la memoria) una variable anónima de tipo Something. En términos de valores, main.&s != gotest.&s, main.s == gotest.s, main.*s == gotest.*s y main.s.number == gotest.s.number.

Debe seguir los consejos de mkb y dejar de usar println(&s). Utilice el paquete fmt, por ejemplo,

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

punteros tienen el mismo valor cuando apuntan a la misma posición de memoria; los punteros tienen diferentes valores cuando apuntan a diferentes ubicaciones de memoria.

+0

En mi ejemplo, el más usado toma un puntero a 'Algo', así que supongo que se refiere al mismo objeto, y claramente lo es, ya que después de cambiar el valor dentro de la rutina, el objeto también tiene su valor cambiado en el principal función. El valor del puntero impreso es diferente. –

+0

@JamesDean En su ejemplo, está imprimiendo el valor del puntero & s tipo ** Algo, que no es lo mismo que el valor del puntero s tipo * Algo. Revisé mi ejemplo para pasar un puntero por valor. – peterSO

+0

@James Dean Imprimió la dirección del puntero (es decir, un puntero al puntero 's'), - los punteros se pasan por valor, la dirección de' s' no es lo mismo que 's'. Si su función más deseada fue 'println (s)' intead, imprimiría el valor del puntero. – nos

1
type sometype struct { } 
a := sometype {} 
b := int(2) 
println("Ptr to a", &a) 
println("Ptr to b", &b) 
+4

No use la orden interna println pero el uso de algo apropiado del paquete fmt: http: // golang .org/doc/go_spec.html # Bootstrapping – mkb

5

En Go, los argumentos se pasan por valor.

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

Salida:

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

Esto no parece correcto, ¿por qué no puedo pasar un puntero? 'func f (s * SomeStruct) {' –

+0

@MattJoiner: Correcto. Puedes pasar un puntero. He revisado el ejemplo para mostrarte cómo. – peterSO

+0

Este lenguaje tiene un gran potencial. –

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

SALIDA:

$ go run pointers.go 
initial: 1 
zeroval: 1 
zeroptr: 0 
pointer: 0x42131100 
1

¿Cómo print el valor del puntero de un objeto de Ir?

package main 

import (
    "fmt" 
) 

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

resultados en:

0x1040a124 

¿Qué significa el valor del puntero?

Según Wikipedia:

Un puntero hace referencia a una ubicación en la memoria

Cuestiones relacionadas