web-dev-qa-db-fra.com

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

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 avaient adopté uniquement des références (avec les qualificatifs const ou mutable appropriés). Nous avons maintenant des pointeurs et pour certains types intégrés comme les cartes et les canaux passent implicitement par référence.

Suis-je en train de manquer quelque chose ou les pointeurs de Go sont-ils une complication inutile?

82
anon

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
}
37

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.

32
zildjohn01

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 structures Point sont intégrées dans la structure LineSegment. Mais vous ne pouvez pas toujours intégrer directement les données. Si vous souhaitez prendre en charge des structures telles que des arbres binaires ou une liste liée, vous devez prendre en charge une sorte de pointeur.

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

Java, Python etc n'a pas ce problème car il ne vous permet pas d'incorporer des types composites, il n'est donc pas nécessaire de différencier syntaxiquement 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 struct et class comme C # et Swift le fait. Mais cela a des limites. Bien que vous puissiez généralement spécifier qu'une fonction prend une structure comme paramètre inout 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 trouver 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 (cela est très simplifié avec beaucoup de contrôles supprimés pour simplement montrer 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
}

Échanger deux valeurs

Les pointeurs vous permettent également d'implémenter swap. Cela consiste à échanger 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 sur la même étendue en raison du manque de capacité à contrôler la disposition et l'utilisation de la mémoire (les échecs de cache affectent considérablement les performances). Go a visé à remplacer C++ dans de nombreux domaines et doit donc prendre en charge les pointeurs.

31
Erik Engheim

Go est conçu pour être un langage laconique et minimaliste. Cela 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.


The Go Programming Language: Language Design FAQ: Pourquoi les cartes, les tranches et les canaux font-ils référence 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 avec le fonctionnement des tableaux. Finalement, nous avons décidé que la séparation stricte des pointeurs et des valeurs ont rendu 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 grand effet sur l'utilisabilité: Go est devenu un un langage plus productif et confortable lors de leur introduction. "


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


golang-noix: allez langue. Quelques commentaires 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 être avantageux de marquer des objets immuables d'une manière ou d'une autre, nous ne pensons pas qu'un qualificatif de type const soit à la manière aller."

27
peterSO