Los 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)
}
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 int
variable en la ubicación de la memoria ( &i
) 0xf800000040
con un valor inicial ( i
) 42
.
En función main
, p
es un puntero a una int
variable en la ubicación de la memoria ( &p
) 0xf8000000f0
con un valor ( p
= &i
) 0xf800000040
que apunta a un int
valor ( *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 la memoria ( &p
) 0xf8000000f0
al byval
parámetro de la función q
en la ubicación de la memoria ( &q
) 0xf8000000d8
. En otras palabras, se asigna memoria para el byval
parámetro q
y se le asigna el valor del main
byval
argumento p
; los valores de p
y q
son inicialmente los mismos, pero las variables p
y q
son distintas.
En función byval
, usando pointer q
( *int
), que es una copia de pointer p
( *int
), integer *q
( i
) se establece en un nuevo valor int 4143
. Al final antes de regresar. el puntero q
se establece en nil
(valor cero), lo que no tiene ningún efecto sobre p
ya que q
es una copia.
En función main
, p
es un puntero a una int
variable en la ubicación de la memoria ( &p
) 0xf8000000f0
con un valor ( p
= &i
) 0xf800000040
que apunta a un nuevo int
valor ( *p
= i
) 4143
.
En función main
, i
es una int
variable en la ubicación de la memoria ( &i
) 0xf800000040
con un valor final ( i
) 4143
.
En su ejemplo, la main
variable de función s
utilizada como argumento para la gotest
llamada a la función no es la misma que el gotest
parámetro de la función s
. 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 a la 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 ubicación de la memoria para la variable s
en la función main
que se usa como argumento para la llamada a la función gotest(s, done)
, y 0x4974d8
es la dirección de la ubicación de la memoria para el gotest
parámetro de la función s
. Si establece el parámetro s = nil
al final de la función gotest
, no tiene ningún efecto en la variable s
en main
; s
en main
y s
en gotest
son ubicaciones de memoria distintas. En términos de tipos, &s
es **Something
, s
es *Something
y *s
es Something
. &s
es un puntero a (dirección de ubicación de memoria) s
, que es un puntero a (dirección de ubicación de memoria) una variable anónima de tipoSomething
. En cuanto a los valores, main.&s != gotest.&s
, main.s == gotest.s
, main.*s == gotest.*s
, y main.s.number == gotest.s.number
.
Debe seguir el sabio consejo de mkb y dejar de usarlo println(&s)
. Utilice el fmt
paquete, por ejemplo,
fmt.Printf("%v %p %v\n", &s, s, *s)
Los punteros tienen el mismo valor cuando apuntan a la misma ubicación de memoria; Los punteros tienen valores diferentes cuando apuntan a diferentes ubicaciones de memoria.