Maison  >  Article  >  développement back-end  >  Des pas de bébé avec Go

Des pas de bébé avec Go

WBOY
WBOYoriginal
2024-08-05 19:28:13305parcourir

Baby steps with Go

J'ai décidé d'essayer Go au cours de mon voyage pour apprendre une nouvelle langue qui serait utile à ma carrière et à mes intérêts. Cette fois, j'ai essayé Go. Je pense qu'au vu des premières impressions, c'est plutôt sympa.

Ceci n'est pas une visite guidée, et sans doute, elle n'est pas écrite pour quelqu'un d'autre que moi, comme quelques rappels personnels.

Je me suis donné un petit projet pour cela appelé Os-Release-Q . Mon intention était de pouvoir avoir un binaire sur n'importe quel système que je gère, de sorte que je puisse imprimer exactement les informations dont j'ai besoin, sans avoir besoin de les analyser ou de les rechercher.

Premier obstacle : importer

La recherche sur le Web parle beaucoup d'importer les packages d'autres personnes, mais très peu d'organiser son propre code. Même les documents se concentrent sur la recherche plutôt que sur la séparation des préoccupations.

Je rencontre cet obstacle un peu dans toutes les langues, car chacune a sa propre philosophie idiosyncrasique sur la façon de s'y prendre et les limites que chacune a ou impose.

De toutes les activités que j'ai entreprises pour apprendre les bases, venant d'un milieu principalement python, diviser mon code en plusieurs fichiers était ce qui m'a pris le plus de temps pour obtenir des réponses. En résumé, j'ai trouvé ce qui suit :

  • le niveau supérieur a besoin d'un go.mod déclarant le nom du module du module
  • Je peux ensuite définir un répertoire src/ au niveau supérieur, et un src/main.go dans lequel placer ma fonction principale, avec une déclaration main du package en haut
  • mettre du code dans d'autres fichiers est aussi simple que de créer un fichier comme src/others.go avec une déclaration principale du package.
  • Toutes les fonctions et variables deviennent disponibles directement dans n'importe quel autre fichier du package main , mais les fichiers doivent être explicitement indiqués lors de l'appel FILES de build

Pour les sous-modules locaux, le sous-module doit résider dans un dossier. Il peut déclarer un package submodule-name .

Dites que c'est dans src/submod/, avec l'implémenteur principal dans src/submod/submod.go. Dans main.go, nous importons "nom-module/src/submod" (avec le nom du module extrait de go.mod). Et puis nous pouvons appeler submod.SomeFunction().

Nous notons que les fonctions des sous-modules ne sont disponibles pour les importateurs que si leur nom commence par une lettre majuscule. Donc ne faites pas submod.myFunction() - ça doit être submod.MyFunction().

Il y a sûrement d'autres considérations concernant les sous-modules et les importations, mais en ce qui concerne l'organisation et la séparation du code, c'est l'essentiel.

Pour garder les choses saines, j'ai tenté de n'avoir qu'un seul fichier déclarant le package principal et d'isoler le reste dans des sous-modules - ceux-ci sont importés automatiquement sans avoir besoin d'être déclarés dans la liste de fichiers go build FILES.

Effectuer des tâches de base

Après avoir résolu cette spécificité du Go, le reste s'est mis en place assez facilement. Pour chaque tâche de base il y avait bien sûr une entrée StackOverflow, ou une page GoByExample.com, et plus fondamentalement, la référence du langage Go.

  • La gestion des chaînes se fait via le package strings
  • La gestion des tableaux a un certain nombre de fonctions natives, dont le modèle base_array = append(base_array, item1, item2) - il fonctionne également pour étendre un tableau avec les valeurs d'un autre via append(base, other_array...)
  • La gestion des erreurs se fait généralement en distribuant des objets d'erreur, mais pas nécessairement.
  • une bibliothèque "log" existe pour un journal préconfiguré et pratique. Il comprend un appel log.Fatal(message) qui enregistre une erreur et se ferme immédiatement.
  • L'appel des sous-processus est facile via la bibliothèque "os/exec", en utilisant le modèle exec.Command(base, args...)

Deux tâches particulièrement courantes méritent leurs propres paragraphes.

Gestion des erreurs

La gestion des erreurs de base est souvent considérée comme lourde, nécessitant littéralement de gérer les erreurs au milieu du flux de contrôle. Cela peut être un anathème pour les programmeurs issus d'un workflow try/catch, mais gérer le problème au point où il peut se produire n'est pas si mal.

// explicit return item `err` forces us to be aware of it
// but having the ability to check it in the same breath is not so bad
if result, err := someCall(); err != nil {
    log.Fatal("Sorry.")
}

// Equally valid is
/*
result, err := someCall()
if err != nil {
    log.Fatal("Sorry")
}
*/

fmt.Println(result)

Comparez la méthode try/catch

try:
    result = someCall()
    print(result)
except:
    print("Sorry") # a little divorced from potential origin of error
    sys.exit(1)

Analyse des arguments

Je ne peux m'empêcher de penser que l'implémentation de la bibliothèque de drapeaux est un peu à moitié cuite. De toute évidence, les gens y sont habitués et sont d’accord, étant donné sa survie sous sa forme actuelle.

L'appel du programme -flag arg1 arg2 nous donne la bascule pour laquelle flag est configuré, et positionals := flags.Args() nous renvoie le tableau de ["arg1", "arg2"]

Cependant, l'appel du programme arg1 arg2 -flag ne pas basculer ce que -flags est censé faire, et donne à la place ses positions comme ["arg1", "arg2", "-flag"] dans lequel le drapeau n'a pas été analysé.

Cela peut être utile pour transmettre un sous-appel comme program colorize ls -l où le ls -l est transmis littéralement - afin que je puisse voir un cas d'utilisation.

C'est juste que la plupart des programmes permettent de signaler des arguments n'importe où autour des éléments de position. ls dir1/ -l dir2/ est identique à ls -l dir1/ dir2/, et c'est une convention qui s'applique à la grande majorité des commandes Unix et Linux.

C'est peut-être juste que c'est quelque chose auquel il faut s'habituer - et qui mérite d'être signalé.

Objectif et cas d'utilisation de Go

Mis à part le paradigme d’importation de fichiers, j’ai trouvé assez facile de mettre en œuvre mon application de base. Tout ce que je faisais de mal me paraissait assez évident et les erreurs étaient significatives. J'ai vraiment l'impression que je peux simplement me concentrer sur "faire avancer les choses".

D'après ma très faible utilisation jusqu'à présent, et en tenant compte de mes besoins spécifiques, je peux voir

  • facile à démarrer
  • binaire compilé, aucune dépendance d'exécution
  • un langage simple avec des types est une avancée par rapport aux scripts shell
  • prise en charge du multitraitement prétendument facile

Je pensais qu'avoir des types clairsemés au lieu d'objets et d'héritage serait un obstacle, mais jusqu'ici tout va bien. Je m'en passe sans eux dans d'autres langages, donc je suppose que lorsque je définirai des interfaces et des types, cela ressemblera à une avancée par rapport à Lua et bash. J'espère.

L'une des raisons pour lesquelles je voulais explorer un langage compilé vers natif était de pouvoir produire des binaires qui pourraient facilement être déplacés, sans avoir besoin de compter sur la présence d'une version particulière d'un runtime.

Un collègue s'est récemment présenté à mon bureau avec consternation, essayant de résoudre l'installation de Java 17 sur une ancienne image de base Node basée sur Debian 10. Soit il devrait mettre à niveau la version de Node pour obtenir une image de base plus récente, utiliser une nouvelle image de base Debian et installer et configurer Node manuellement, soit parcourir Internet à la recherche d'un dépôt personnalisé hébergé par Dieu sait qui pour Dieu sait. -si Java 17 était piraté, il fonctionnerait sur Debian 10.

Comme c'est beaucoup plus facile si le logiciel déployé n'avait pas de dépendances d'exécution conflictuelles...

D'un point de vue opérationnel, le seul gros gain que je pense pouvoir ressentir est le suivant : je peux facilement écrire du code et créer un binaire ELF pour ensuite le déployer sur un "système arbitraire X" sans avoir à faire face à s'assurer que la bonne version d'un runtime donné est en place et gérer les dépendances conflictuelles.

Je suis sûr qu'il y a d'autres avantages, et j'ai beaucoup entendu parler de la facilité d'utilisation du multithreading et du multitraitement dans Go, et j'ai l'intention de préparer un mini-projet pour explorer cela dans la prochaine étape - probablement quelque chose qui pourrait écouter les entrées sur plusieurs canaux et effectuer certaines tâches de base en réponse. J'ai eu un cas d'utilisation pour cela dans certaines tâches d'automatisation de tests que j'ai déjà effectuées, donc cela ne m'est pas étranger à ce stade.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn