2017-06-11 4 views
-2

Dans le premier cas je passe une carte par valeur: paquet principalmutation étrange de la carte lorsque la valeur passée vs lorsqu'il est passé par référence (golang)

import (
    "fmt" 
    "time" 
) 

func timeMap(z map[string]interface{}) { 
    z["updated_at"] = time.Now() 
} 

func main() { 
    foo := map[string]interface{}{ 
     "Matt": 42, 
    } 
    timeMap(foo) 
    fmt.Println(foo) 
} 

La sortie est une carte en sourdine:

map[updated_at:2009-11-10 23:00:00 +0000 UTC Matt:42] 

Dans le second cas le code est presque identique, mais pour le passage par référence:

package main 

import (
    "fmt" 
    "time" 
) 

func timeMap(z *map[string]interface{}) { 
    (*z)["updated_at"] = time.Now() 
} 

func main() { 
    foo := map[string]interface{}{ 
     "Matt": 42, 
    } 
    timeMap(&foo) 
    fmt.Println(foo) 
} 

De toute évidence, le résultat est différent:

map[Matt:42 updated_at:2009-11-10 23:00:00 +0000 UTC] 

Mes attentes étaient les suivantes:

  • en passant par la carte de valeur est pas mis en sourdine
  • Lors du passage par carte de référence est mis en sourdine comme dans le deuxième cas. Cependant, dans la première carte de cas a été coupé, mais dans l'ordre inverse (par rapport au deuxième cas).

Pourquoi cela arrive-t-il?

+0

1) [Pourquoi une valeur de carte dans une fonction affectée par une entrée à la carte dans une autre fonction?] (Https://stackoverflow.com/questions/39605295/why-is-a-map -value-dans-une-fonction-affectée-par-une-entrée-à-la-carte-dans-autre-fu/39605565 # 39605565); et 2) [Pourquoi ne peut pas aller cartes Iterate afin d'insertion?] (https://stackoverflow.com/questions/28930416/why-cant-go-iterate-maps-in-insertion-order/28931555#28931555) – icza

+1

Go n'a pas la notion de "passage par référence", donc votre question n'a aucun sens. Arrêtez de penser aux pointeurs comme "passer par référence". Ce n'est pas. – Volker

Répondre

3

Il n'y a pas de passage par référence dans Go. Chaque fois que vous passez quelque chose (pointeur, en-tête de tranche, carte), il est toujours passé par valeur. La question est de savoir exactement ce qui est passé en valeur (c'est-à-dire quel est le value réel du type).

Lorsque u passer une carte, vous passez une copie de le pointeur à son en-tête, qui contient un ensemble de pointeurs vers les seaux, comme dans la mise en œuvre de la Hashtable. https://github.com/golang/go/blob/master/src/runtime/hashmap.go#L106

Par conséquent, il est rarement judicieux de passer un pointeur sur la carte, car l'opération de copie d'un pointeur d'en-tête de carte est extrêmement bon marché.

Maintenant, pourquoi la commande est différente, cela est simplement dû à la mise en œuvre interne de la carte, allant sur les touches se produit de manière aléatoire. Encore une fois ce n'est qu'un détail d'implémentation.

EDIT:

Comme @icza a souligné à juste titre, en passant une carte passe en fait une copie d'un pointeur à l'en-tête de la carte, pas l'en-tête de la carte elle-même. Désolé pour la confusion

+0

Il s'agit d'un détail d'implémentation, mais si vous écrivez à ce sujet, le fait de passer une valeur de carte passe/copie un seul ** pointeur ** à une valeur de 'runtime.hmap'. Passer une copie de l'en-tête serait mauvais car tous les champs ne sont pas des pointeurs (et modifier, par exemple, le champ 'count' - qui est la longueur - ne serait pas reflété à l'appelant). – icza

+0

oui, vous avez absolument raison – Yerken