2 votes

Essayer d'appréhender les pointeurs de Go

J'ai écrit un petit snippet pour parcourir récursivement un répertoire et retourner une tranche de fichiers ( []string ) en fonction de l'extension. Cela semble fonctionner, mais je n'arrive pas à saisir pleinement l'idée derrière les pointeurs et comment l'utiliser correctement.

package main

import (
    "path/filepath"
    "io/ioutil"
    "fmt"
)

// aggregator slice should hold the result (a slice of filepaths)
// dir is the current directory being listed
// exts is a slice of extensions that should be included in the result
func recurse(aggregator *[]string, dir string, exts *[]string) []string {
    files, _ := ioutil.ReadDir(dir)
    for _, file := range files {
        // current filepath
        path := filepath.Join(dir, file.Name())

        // if directory, recursively analyze it
        if file.IsDir() {
            *aggregator = recurse(aggregator, path, exts)

        // else check if file is of proper extension and add it to aggregator
        } else {
            for _, ext := range *exts {
                if (filepath.Ext(path) == ext) {
                    *aggregator = append(*aggregator, path)
                    break
                }
            }
        }
    }
    return *aggregator
}

func getTemplates(templatesDir string, templatesExtensions ...string) {
    templates := recurse(&[]string{}, templatesDir, &templatesExtensions)

    // for testing purposes just print filepaths
    for _, t := range templates {
        fmt.Printf("%s\n", t)
    }
}

func main() {
    getTemplates("./templates", ".tmpl", ".html")
}

La question principale est d'utiliser *aggregator ( aggregator *[]string ), &[]string{} y *exts ( exts *[]string ). Je viens de javascript Un monde où chaque objet est fondamentalement un pointeur et où vous ne pouvez copier des objets et des tableaux que de manière explicite. Ici, d'un autre côté, il semble que si je n'utilisais pas de pointeurs ( *aggregator etc.), ces objets seraient copiés à chaque itération de la fonction.

Est-ce que cette approche est correcte ou est-ce que je rate quelque chose ?

2voto

Kaveh Shahbazian Points 3674

Bien que cette visualisation ne concerne pas spécifiquement le Go (elle concerne Java), elle est parfaite pour visualiser l'utilisation des pointeurs et des valeurs (1) : enter image description here

Comme vous le voyez, un pointeur n'est pas réellement contient aucune donnée, mais il Les points suivants l'endroit où résident les données. Ainsi, toute modification apportée à ces données via un pointeur est en fait effectuée sur les données elles-mêmes. Mais les données ne résident pas nécessairement là où notre pointeur est utilisé.

Il existe différentes situations dans lesquelles nous pouvons avoir besoin de pointeurs. Par exemple, lorsque vous souhaitez modifier les valeurs réelles à un endroit précis (et ne pas les transmettre) ou lorsque vos données sont trop volumineuses et que le coût de transmission du contenu réel est trop élevé. Vous pouvez utiliser un/des pointeur(s) vers ces grandes données et tout le monde (chaque fonction par exemple) qui a un pointeur vers ces données, peut les lire ou les modifier. Et comme nous venons de le dire, nous pouvons avoir autant de pointeurs vers les mêmes données que nécessaire. Il peut donc y avoir plusieurs pointeurs vers une seule et même donnée. La valeur de ces pointeurs est la même, c'est-à-dire l'adresse de la donnée source (objet).

Oublié d'ajouter des tranches dans Go serait passé par le pointeur / référence, mais vous ne pouvez pas modifier la tranche (ajouter / supprimer des éléments). Vous pouvez cependant modifier ses éléments. Si vous devez modifier la tranche elle-même, alors vous devez utiliser un pointeur vers la tranche. Sinon, si vous le passez simplement comme un conteneur de certaines valeurs, vous n'avez pas à vous inquiéter car elles ne seront pas copiées à chaque fois.

(1) Source :

0voto

silvergasp Points 855

Les tranches de go sont des types de référence, ainsi que les cartes et les pointeurs (je suis presque sûr que les chaînes de caractères le sont aussi, mais ne me posez pas de questions à ce sujet :). aquí pour une discussion à ce sujet). Ces types particuliers sont donc automatiquement transmis par référence. La variable elle-même est donc évaluée comme un pointeur dont la valeur est l'adresse de référence. Donc, dans votre cas, il serait sûr et probablement préférable de modifier aggregator *[]string a aggregator []string et vos données pas être copié, juste une référence passée. Bien sûr, avec ce changement, vous devrez modifier tout le code qui déréférençait auparavant aggregator par exemple

// Change this line
*aggregator = append(*aggregator, path)
// To this
aggregator = append(aggregator, path)

Le raisonnement pour faire cela viendrait probablement des langages basés sur le C où les tableaux sont simplement des pointeurs vers le début de la mémoire allouée.

Nota: Tous les autres types, y compris les structs, ne suivent pas ce modèle (les interfaces sont une autre exception intéressante). lire ). De plus, ce code semble pouvoir être grandement simplifié en utilisant les éléments suivants filepath.Walk() .

Pour un peu plus d'informations, bien que plus ciblées sur les cartes, voir este blog post.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X