Les arguments de la fonction Go sont passés par valeur.
Tout d'abord, laissons de côté les parties non pertinentes de votre exemple, afin de pouvoir voir clairement que vous passez simplement un argument par valeur. Par exemple,
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)
}
Résultat :
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
Dans la fonction main
, i
est une variable de type int
à l'emplacement mémoire (&i
) 0xf800000040
avec une valeur initiale (i
) 42
.
Dans la fonction main
, p
est un pointeur vers une variable de type int
à l'emplacement mémoire (&p
) 0xf8000000f0
avec une valeur (p
\=&i
) 0xf800000040
qui pointe vers une valeur de type int
(*p
\=i
) 42
.
Dans la fonction main
, byval(p)
est un appel de fonction qui assigne la valeur (p
\=&i
) 0xf800000040
de l'argument à l'emplacement mémoire (&p
) 0xf8000000f0
au paramètre de la fonction byval
q
à l'emplacement mémoire (&q
) 0xf8000000d8
. En d'autres termes, de la mémoire est allouée pour le paramètre q
de byval
et la valeur de l'argument de main
byval
p
lui est assignée ; les valeurs de p
et q
sont initialement les mêmes, mais les variables p
et q
sont distinctes.
Dans la fonction byval
, en utilisant le pointeur q
(*int
), qui est une copie du pointeur p
(*int
), l'entier *q
(i
) est configuré avec une nouvelle valeur int 4143
. À la fin avant de retourner, le pointeur q
est défini sur nil
(valeur zéro), ce qui n'a aucun effet sur p
puisque q
est une copie.
Dans la fonction main
, p
est un pointeur vers une variable de type int
à l'emplacement mémoire (&p
) 0xf8000000f0
avec une valeur (p
\=&i
) 0xf800000040
qui pointe vers une nouvelle valeur de type int
(*p
\=i
) 4143
.
Dans la fonction main
, i
est une variable de type int
à l'emplacement mémoire (&i
) 0xf800000040
avec une valeur finale (i
) 4143
.
Dans votre exemple, la variable de la fonction main
s
utilisée comme argument pour l'appel de la fonction gotest
n'est pas la même que le paramètre de la fonction gotest
s
. Ils ont le même nom, mais ce sont des variables différentes avec des portées et des emplacements mémoire différents. Le paramètre de la fonction s
masque l'argument de l'appel de fonction s
. C'est pourquoi dans mon exemple, j'ai nommé les variables d'argument et de paramètre p
et q
respectivement pour souligner la différence.
Dans votre exemple, (&s
) 0x4930d4
est l'adresse de l'emplacement mémoire de la variable s
dans la fonction main
qui est utilisée comme argument pour l'appel de fonction gotest(s, done)
, et 0x4974d8
est l'adresse de l'emplacement mémoire du paramètre de la fonction gotest
s
. Si vous définissez le paramètre s = nil
à la fin de la fonction gotest
, cela n'a aucun effet sur la variable s
dans main
; s
dans main
et s
dans gotest
sont des emplacements mémoire distincts. En termes de types, &s
est **QuelqueChose
, s
est *QuelqueChose
, et *s
est QuelqueChose
. &s
est un pointeur vers (adresse de l'emplacement mémoire) s
, qui est un pointeur vers (adresse de l'emplacement mémoire) une variable anonyme de type QuelqueChose
. En termes de valeurs, main.&s != gotest.&s
, main.s == gotest.s
, main.*s == gotest.*s
, et main.s.number == gotest.s.number
.
Vous devriez suivre le sage conseil de mkb et arrêter d'utiliser println(&s)
. Utilisez le package fmt
, par exemple,
fmt.Printf("%v %p %v\n", &s, s, *s)
Les pointeurs ont la même valeur lorsqu'ils pointent vers le même emplacement mémoire ; les pointeurs ont des valeurs différentes lorsqu'ils pointent vers des emplacements mémoire différents.