J'ai récemment commencé à apprendre le GoLang. Il y a eu plusieurs cas où le compilateur génère une erreur lorsque j'essaie de passer des variables comme arguments dans les fonctions Go. J'ai pu déboguer cela parfois en utilisant un pointeur devant la variable. Les pointeurs & et * semblent effacer l'erreur. Mais j'aimerais comprendre pourquoi. Je me demande quelle est la différence entre &, et *, et quand chacun doit être utilisé. Je vous remercie!
func (ctx *NewContext) SendNotification(rw http.ResponseWriter, req *http.Request, p httprouter.Params) {
decoder := json.NewDecoder(req.Body)
var u User
if err := decoder.Decode(&u); err != nil {
http.Error(rw, "could not decode request", http.StatusBadRequest)
return
}
}
Dans votre exemple ci-dessus, vous avez défini u comme type User, mais pas comme pointeur vers un utilisateur. Vous avez donc besoin du & u car la fonction Decode du package json attend une adresse ou un pointeur.
Si vous avez créé l'instance de User comme ceci: u: = new (User), ce serait un pointeur puisque la nouvelle fonction retourne un pointeur. Vous pouvez également créer un pointeur vers un utilisateur comme celui-ci: var u * User. Si vous avez fait l'un ou l'autre de ces éléments, vous devrez retirer le &
dans l'appel à Decode pour que cela fonctionne.
Les pointeurs sont essentiellement des variables qui contiennent des adresses. Lorsque vous placez le & devant une variable, il renvoie l'adresse. Le * pourrait être lu comme "redirection de". Ainsi, lorsque vous créez un pointeur comme celui-ci:
var x * int
Cela peut être lu car x redirigera vers un int. Et lorsque vous attribuez une valeur à x, vous lui donnez une adresse comme celle-ci: y: = 10 x = & y
Où y est un int. Donc, si vous imprimez x, vous obtiendrez l'adresse de y, mais si vous imprimez * x, vous redirigerez vers ce que x pointe vers la valeur de y qui est 10. Si vous imprimez & x, vous obtiendrait l'adresse du pointeur, x, lui-même.
Si vous essayez d'imprimer * y, qui est juste un int, pas un pointeur, cela générera une erreur car vous redirigerez avec une valeur qui n'est pas une adresse vers laquelle rediriger.
Exécutez ci-dessous pour vous amuser avec le pointeur:
package main
import "fmt"
func main() {
var y int
var pointerToY *int
var pointerToPointerToInt **int
y = 10
pointerToY = &y
pointerToPointerToInt = &pointerToY
fmt.Println("y: ", y)
fmt.Println("pointerToY: ", pointerToY)
fmt.Println("pointerToPointerToInt: ", pointerToPointerToInt)
fmt.Println("&y: ", &y) // address of y
fmt.Println("&pointerToY: ", &pointerToY)// address of pointerToY
fmt.Println("&pointerToPointerToInt: ", &pointerToPointerToInt) // address of pointerToPointerToInt
// fmt.Println(*y) throws an error because
// you can't redirect without an address..
// y only has int value of 10
fmt.Println("*pointerToY: ", *pointerToY) // gives the value of y
fmt.Println("*pointerToPointerToInt: ", *pointerToPointerToInt) // gives the value of pointerToY which is the address of y
fmt.Println("**pointerToPointerToInt: ", **pointerToPointerToInt) // this gives 10, because we are redirecting twice to get y
if pointerToY == *pointerToPointerToInt {
fmt.Println("'pointerToY == *pointerToPointerToInt' are the same!")
}
if pointerToY == &y {
fmt.Println("'pointerToY == &y' are the same!")
}
if &pointerToY == pointerToPointerToInt {
fmt.Println("'&pointerToY == pointerToPointerToInt' are the same!")
}
if y == **pointerToPointerToInt {
fmt.Println("'y == **pointerToPointerToInt' are the same!")
}
if pointerToY == *pointerToPointerToInt {
fmt.Println("'pointerToY == *pointerToPointerToInt' are the same!")
}
}
J'espère que cela t'aides!
Je vais citer un mec intelligent:
& devant le nom de la variable est utilisé pour récupérer l'adresse de stockage de la valeur de cette variable. Cette adresse est ce que le pointeur va stocker.
* devant un nom de type, signifie que la variable déclarée stockera une adresse d'une autre variable de ce type (pas une valeur de ce type).
* devant une variable de type pointeur est utilisé pour récupérer une valeur stockée à une adresse donnée. Dans Go Speak, cela s'appelle le déréférencement.
source: http://piotrzurek.net/2013/09/20/pointers-in-go.html
pointer
est utilisé pour pointer vers address
et il stocke l'adresse mémoire
Ajout d'un exemple pour mieux comprendre pointer
vs address
:
package main
import "fmt"
func main() {
var y int
var pointerToY *int
var x int
//var willThrowErrorVariable int
y = 10
pointerToY = &y
//willThrowErrorVariable = &y
x = *pointerToY
fmt.Println("y: ",y)
fmt.Println("y's address using pointerToY: ",pointerToY)
y = 4
fmt.Println("====================================================")
fmt.Println("Address of y after its value is changed: ",pointerToY)
fmt.Println("value of y using pointer after its value is changed: ",*pointerToY)
fmt.Println("Value of x after y value is changed: ",x)
}
production
y: 10
y's address using pointerToY: 0x414020
====================================================
Address of y after its value is changed: 0x414020
value of y using pointer after its value is changed: 4
Value of x after y value is changed: 10
Comme nous pouvons le voir, la valeur peut changer mais le address
(&
) reste le même et donc le pointer
(*
) pointe sur la valeur de address
.
Dans l'exemple ci-dessus,
pointerToY
contient le pointeur pour faire référence à address
de y
.x
contient la valeur que nous lui transmettons en utilisant pointer
à address
de y
.y
, le x
a toujours 10
mais si nous essayons d'accéder à la valeur en utilisant pointer
à address
( pointerToY ), nous obtenons 4