Quel est l'intérêt d'avoir des pointeurs dans Go?

100

Je sais que les pointeurs dans Go permettent la mutation des arguments d'une fonction, mais cela n'aurait-il pas été plus simple s'ils n'adoptaient que des références (avec des qualificatifs const ou mutables appropriés). Maintenant, nous avons des pointeurs et pour certains types intégrés tels que les cartes et les canaux, un passage implicite par référence.

Est-ce que je manque quelque chose ou les pointeurs dans Go sont-ils simplement une complication inutile?

anon
la source
1
Voici une question qui peut aider à clarifier: stackoverflow.com/questions/795160/ ... Il y a une différence entre passer des références par valeur et passer vraiment par référence.
R. Martinho Fernandes
1
Remarque: la question concerne Java, mais elle s'applique également ici.
R. Martinho Fernandes
1
"et pour certains types intégrés comme les cartes et les canaux, le passage implicite par référence." Non, tout est pass-by-value dans Go. Certains types sont (officieusement décrits comme) des types de référence, car ils ont un état mutable interne.
newacct
Le problème avec cette question est que les «références» ne sont pas une seule chose avec des propriétés bien définies. Le terme «références» est très vague. Nous pouvons voir dans les réponses combien de personnes lisent différentes choses dans le mot «références». Cette question devrait donc préciser quelles différences il y a entre les pointeurs Go et les références que la question a à l'esprit.
mtraceur

Réponses:

36

J'aime vraiment l'exemple tiré de http://www.golang-book.com/8

func zero(x int) {
    x = 0
}
func main() {
    x := 5
    zero(x)
    fmt.Println(x) // x is still 5
}

en contraste avec

func zero(xPtr *int) {
    *xPtr = 0
}
func main() {
    x := 5
    zero(&x)
    fmt.Println(x) // x is 0
}
Piotr Kochański
la source
42
La question était "pourquoi avons-nous des pointeurs au lieu de références " et je ne comprends pas pourquoi cet exemple ne fonctionnerait pas avec des références.
AndreKR
@AndreKR Parce que nous pouvons choisir de passer par référence ou de passer par valeur. Dans certains cas, les deux peuvent être souhaitables.
JDSweetBeat
9
@DJMethaneMan C'est "pointeurs vs références", pas "pointeurs vs pass-by-value"!
AndreKR
En guise de commentaire parallèle, le passage par référence a été ajouté dans C # 2.0 via le mot-clé "ref". Bien sûr, les pointeurs sont encore plus pratiques dans certains cas, car nous pouvons avoir un pointeur vers un pointeur vers un pointeur ...
robbie fan
Je ne comprends pas comment Go est censé être l'un des langages les plus populaires et pourtant ils contiennent une telle "fonctionnalité" ... C'est déroutant et semble inutile, du moins pour les gens qui le signalent ici.
Akito
33

Les pointeurs sont utiles pour plusieurs raisons. Les pointeurs permettent de contrôler la disposition de la mémoire (affecte l'efficacité du cache du processeur). Dans Go, nous pouvons définir une structure où tous les membres sont en mémoire contiguë:

type Point struct {
  x, y int
}

type LineSegment struct {
  source, destination Point
}

Dans ce cas, les Pointstructures sont intégrées dans la LineSegmentstructure. Mais vous ne pouvez pas toujours intégrer directement des données. Si vous souhaitez prendre en charge des structures telles que des arbres binaires ou des listes chaînées, vous devez prendre en charge une sorte de pointeur.

type TreeNode {
  value int
  left  *TreeNode
  right *TreeNode
}

Java, Python, etc. n'ont pas ce problème car ils ne vous permettent pas d'incorporer des types composites, il n'est donc pas nécessaire de différencier syntaxiquement entre l'incorporation et le pointage.

Problèmes avec les structures Swift / C # résolus avec les pointeurs Go

Une alternative possible pour accomplir la même chose est de faire la différence entre structet classcomme le fait C # et Swift. Mais cela a des limites. Bien que vous puissiez généralement spécifier qu'une fonction prend une structure comme inoutparamètre pour éviter de copier la structure, elle ne vous permet pas de stocker des références (pointeurs) vers des structures. Cela signifie que vous ne pouvez jamais traiter une structure comme un type de référence lorsque vous trouvez cela utile, par exemple pour créer un allocateur de pool (voir ci-dessous).

Allocateur de mémoire personnalisé

En utilisant des pointeurs, vous pouvez également créer votre propre allocateur de pool (ceci est très simplifié avec de nombreuses vérifications supprimées pour ne montrer que le principe):

type TreeNode {
  value int
  left  *TreeNode
  right *TreeNode

  nextFreeNode *TreeNode; // For memory allocation
}

var pool [1024]TreeNode
var firstFreeNode *TreeNode = &pool[0] 

func poolAlloc() *TreeNode {
    node := firstFreeNode
    firstFreeNode  = firstFreeNode.nextFreeNode
    return node
}

func freeNode(node *TreeNode) {
    node.nextFreeNode = firstFreeNode
    firstFreeNode = node
}

Échangez deux valeurs

Les pointeurs vous permettent également de mettre en œuvre swap. C'est permuter les valeurs de deux variables:

func swap(a *int, b *int) {
   temp := *a
   *a = *b
   *b = temp
}

Conclusion

Java n'a jamais été en mesure de remplacer complètement C ++ pour la programmation de systèmes dans des endroits tels que Google, en partie parce que les performances ne peuvent pas être réglées de la même manière en raison du manque de capacité à contrôler la disposition et l'utilisation de la mémoire (les erreurs de cache affectent considérablement les performances). Go a pour objectif de remplacer le C ++ dans de nombreux domaines et doit donc prendre en charge les pointeurs.

Erik Engheim
la source
7
C # permet de passer des structures par référence. Voir les mots clés "ref" et "out".
olegz
1
D'accord, c'est comme Swift. Je vais réfléchir à un moyen de mettre à jour mon exemple.
Erik Engheim
29

Les références ne peuvent pas être réaffectées, contrairement aux pointeurs. Cela seul rend les pointeurs utiles dans de nombreuses situations où les références ne peuvent pas être utilisées.

zildjohn01
la source
17
La réattribution des références est un problème d'implémentation spécifique à la langue.
crantok
28

Go est conçu pour être un langage concis et minimaliste. Il a donc commencé avec juste des valeurs et des pointeurs. Plus tard, par nécessité, certains types de référence (tranches, cartes et canaux) ont été ajoutés.


Le langage de programmation Go: FAQ sur la conception du langage: Pourquoi les cartes, les tranches et les canaux sont-ils des références alors que les tableaux sont des valeurs?

"Il y a beaucoup d'histoire sur ce sujet. Au début, les cartes et les canaux étaient des pointeurs syntaxiquement et il était impossible de déclarer ou d'utiliser une instance sans pointeur. De plus, nous avons eu du mal à savoir comment les tableaux devraient fonctionner. Finalement, nous avons décidé que la séparation stricte de pointeurs et de valeurs rendaient le langage plus difficile à utiliser. L'introduction de types de référence, y compris des tranches pour gérer la forme de référence des tableaux, a résolu ces problèmes. Les types de référence ajoutent une complexité regrettable au langage, mais ils ont un effet important sur la convivialité: Go est devenu un langage plus productif et confortable lors de leur introduction. "


La compilation rapide est un objectif de conception majeur du langage de programmation Go; cela a ses coûts. L'une des pertes semble être la capacité de marquer des variables (à l'exception des constantes de temps de compilation de base) et des paramètres comme immuables. Il a été demandé, mais refusé.


golang-nut: go language. Quelques retours et doutes.

"L'ajout de const au système de types le force à apparaître partout et oblige à le supprimer partout si quelque chose change. Bien qu'il puisse y avoir des avantages à marquer des objets immuables d'une manière ou d'une autre, nous ne pensons pas qu'un qualificatif de type const soit utile aller."

peterSO
la source
FWIW, les «types de référence» dans Go sont également réaffectables. Ils ressemblent plus à des pointeurs implicites?
Matt Joiner
1
Il s'agit simplement d'une syntaxe spéciale pour les structures contenant un pointeur (et une longueur, une capacité, ...).
mk12