# Golang ### Débat - Pourquoi et comment choisit-on un langage de programmation ? ---- ### Histoire Go, aussi appelé Golang, est un langage de programmation open source relativement jeune, développé en 2007 par Robert Griesemer, Rob Pike et Ken Thompson, alors employés chez Google. #### Déclaration des experts à l'origine de Go lors de son lancement > "Chez Google, nous pensons que la programmation devrait être rapide, productive et surtout, fun. C’est pourquoi nous sommes ravis de proposer ce nouveau langage de programmation expérimental. Les opérations de compilation sont presque instantanées, et le code compilé propose une vitesse de fonctionnement proche de celle du C." Pour résumer leur message : le langage de programmation Go rime avec **efficacité** et **simplicité**. Le langage de programmation Go a été lancé en novembre 2009 et est utilisé dans certains systèmes de production de Google - le même qui a été utilisé pour développer le logiciel de conteneurisation Docker ! ### Golang Vs Le monde Syntaxiquement Golang est très semblable au C. Comme ce dernier, le Go est un langage à typage statique. Les types des variables sont connus lors de la compilation et doivent être spécifiés expressément par le programmeur. Mais contrairement au language C, le Go possède une sécurité de mémoire sous forme d'un "Garbage Collector". >Un Garbage Collector (ramasse-miettes, ou récupérateur de mémoire, ou glaneur de cellules) est un sous-système informatique de gestion automatique de la mémoire. Il est responsable du recyclage de la mémoire préalablement allouée puis inutilisée. Golang est très souvent mis à part du Python ou d'autres languages de scripting car ces derniers sont souvent plus simples syntaxiquement. Malgré la simplicité syntaxique similaire, Python reste un langage interprété contrairement a Go qui est un language compilé. ### Langages Compilés VS languages interprétés * Dans un langage interprété, le code source est interprété par un autre logiciel nommé "l’interpréteur" ; celui-ci traduit au fur et à mesure des lignes de votre programme. * Dans un langage compilé, le code source est compilé en langage binaire par un autre logiciel nommé "le compilateur" puis éxcécuté par votre machine. L'avantage du language compilé est que vous n'avez plus besoin de programme tiers pour l'exécuter (tandis qu'un language comme le Python aura toujours besoin de son interpréteur), de plus comme votre code est exécuté directement par votre machine alors le temps d'exécution sera en général plus rapide celui pour le même programme dans un langage interprété. #### Exemple "Mandelbrot". Mandelbrot est un type de fractale. Et des algorithmes pour les générer existent dans beaucoup de langages, ce qui est pratique pour comparer la rapidité d'exécution. >Avec du code Python: Mandelbrot crée en 105 secondes >Avec du code C: Mandelbrot crée en 4 secondes Cependant, les langages de programmation compilés ne sont pas vierges d'ennuis. Chaque modification de votre code source nécessite une recompilation de votre programme. Ensuite, il faut savoir que votre programme compilé n'est pas multi-plateforme, il faudra donc créer un exécutable pour chaque système d’exploitation. Les langages interprétés restent quant à eux généralement multi-plateforme. ### Avantages du langage GO * Une meilleure protection de la mémoire grâce à son ramasse-miettes (Garbage Collector) qui permet une gestion automatique de la mémoire. * Profite de la puissance de calcul des processeurs les plus robustes du marché (processeurs multi-cœurs). * La possibilité de faire du typage dynamique et d'intégrer de nombreux types avancés tels que les mappages clé-valeur. * Possède une riche librairie standard - il est même parfaitement possible de concevoir des programmes écrits avec le langage Go sans aucune dépendance externe. * Une base de code propre nécessaire aussi pour assurer la maintenance et l'évolution des programmes sur plusieurs générations de développeurs. * Possède un temps de compilation rapide et intègre aussi un système de build beaucoup moins compliqué que celui de la plupart des langages compilés. * Au niveau de la portabilité, il est possible de compiler votre code pour une large gamme de systèmes d'exploitation et de plateformes matérielles (Windows, Linux, MAC OS, Android, IOS). * La communauté et la facilité d'utilisation des packages. ### Qui utilise Golang? Liste non exhaustive des entreprises utilisant Go : * CloudFlare * CoreOS * DropBox * Docker * Nokia * Ovh * YouTube * SoundCloud * Splice ### Quelques infos pratiques : #### Les types de variables : | Type | Description | | ------- | -------------------------------------- | | uint | 32 ou 64 bits non signé | | int | même taille que uint mais signé | | float32 | 32 bits (Environ 7 chiffres décimaux) | | float64 | 64 bits (Environ 16 chiffres décimaux) | | bool | true ou false | | byte | identique à uint8 | | string | chaines de caratères (texte) | #### Les conditions et boucles : ```go= // if // if else // else if i != j { } if else i == 2 { } else { } // switch case //i est un chiffre aléatoire entre 1 et 10 i = randomNumber(0, 10) switch i { case 0, 1: //0 ou 1 fmt.println("C'est le premier ou le deuxieme choix") case 3: fmt.println("c'est un choix.") default: fmt.Println("N'importe quel autre choix.") } // for "Classique" for compteur := 0; compteur < 100; compteur++ { /* le code qui sera répété */ } // for a condition condition := 0 for condition > 2 { condition = condition + 1 } // Boucle infini for true { if something { continue // on revient au debut de la boucle } if somethingElse { break // on quitte la boucle } } ``` Pour une liste d'exemple plus fournie : https://learnxinyminutes.com/docs/fr-fr/go-fr/ (Vraiment cool !) ## Premiers Pas 1. Création du projet ```shell= mkdir hello cd hello go mod init hello ``` 2. Création du fichier main.go ```go= package main import ( "fmt" ) func main() { fmt.Println("Comment vont-je?") } ``` ## Fonctions et Fichiers En Golang, tous les fichiers dans un même dossier - nommé "package" - sont considérés comme étant les mêmes fichiers. Une fonction ou variable écrite dans PROJECT/main.go sera accessible dans PROJECT/utility.go et vice-versa. Libre à nous de découper notre code simplement et logiquement. Exemple : >main.go ```go= package main import ( "fmt" ) func main() { fmt.Println(increment(1)) fmt.Println(returnGlobal()) global = increment(global) fmt.Println(returnGlobal()) } ``` >increment.go ```go= package main var ( global int = 1 ) func increment(i int)(int){ return i + 1 } func returnGlobal()(int){ return global } ``` ### Retour multiple L'une des fonctionnalités de Golang est le retour multiple. Celui-ci est possible grâce à une déclaration dans la signature de la fonction. ``` go = func exemple()(int, string){ return 1,"bonjour" } func main(){ nombre, texte := exemple() } ``` ### Structure et Objets Le Golang est un langage qui permet de créer et d'utiliser des objets de manière simple et rapide. Les objets - aussi appelés "class" dans d'autres langages - sont des "struct" en Go. ``` go = type Wizard struct { Name string greeting string magicPower int health int } ``` ### Scope Dans une structure, comme dans un package, nous déclarons le scope (privé, public) de nos variable ou fonction avec la premiere lettre du Nom. ``` go= func main(){ ron := Wizard{Name: "Ron", greeting: "bonjour, je suis ron"} ron.Name //OK Accessible. ron.greeting //NON Pas Accessible } ``` ### Package Les packages font partie des fonctionnements clés de Golang. Toutes nos fonctionnalités, toutes nos lignes de codes sont découpées en packages. Les packages sont un peu comme un fichier en C. Là où en langage C, nous devrions découper les fonctionnalités dans différents fichiers, en Golang nous simplifions le développement grâce aux packages. Un package est un dossier, contenant de multiples fichiers, de codes Go, ou autres. ### TP: Enable Fighting function * L'objectif est de remplir la fonction WizardFight pour arriver au resultat affiché. * *(tips) Vous devez pour cela créer une fonction membre.* >./main.go ```go= package main import ( "hello/poudlard" "fmt" ) func main() { var harry poudlard.Wizard harry = poudlard.CreateWizard("Harry Pointer", "Je suis l'elu, ron.", 10) harry.Greeting() ron := poudlard.CreateWizard("Ron OuiOui", "Je suis l'ami de l'elu", 5) winner, point := poudlard.WizardMatch(&harry, &ron) fmt.Printf("Le gagnant est %s avec %d point d'avance", winner, point) } ``` >./poudlard/poudlard.go ```go= package poudlard import( "fmt" ) var ( DEFAULT_HEALTH int = 100 ) type Wizard struct { Name string greeting string magicPower int health int } func (self Wizard)Greeting(){ fmt.Printf("%s: %s\n", self.Name, self.greeting) } func CreateWizard(name string, greeting string, magicPower int) (Wizard){ return Wizard{ Name: name, greeting: greeting, magicPower: magicPower, health: DEFAULT_HEALTH, } } ``` >./poudlard/fight.go ```go= package poudlard // Fight ... func WizardMatch(one *Wizard, two *Wizard)(string, int) { return "", 0 } ``` > Objectif: ![](https://i.imgur.com/QWLgWh7.png) ### TP: Making life count. #### Modifier la vie. * Ajoutez dans la phrase de Greeting le nombre de points de vie: * >ex: "Harry: je suis l'élu et j'ai 100 points de vie !" * Créez une fonction membre Fight qui prend en paramètre un pointer sur Wizard, et qui modifie la vie en fonction de la puissance magique de l'adversaire. * Dans la fonction WizardMatch, ajoutez l'appel à cette fonction membre Fight pour les deux participants afin d'updater leurs vies. * Dans un duel, les deux magiciens prennent des dégâts. #### Ajouter un historique des matchs dans la structure Wizard * Créez une structure dans poudlard.go nommée **match**, avec comme variables **Name**(string) et **Result** (booléen). * Ajoutez à la structure **Wizard** une variable membre nommée **matchRecord** qui est un slice de ***match**. ```go= matchRecord []match ``` * Créez une fonction membre **addMatch** qui prend comme paramètres un **pointer sur Wizard** (l'autre participant du match) et un **booléen** (le résultat du match). * > Un match gagné est True. Un match perdu ou sans Vainqueur est False. * La fonction **addMatch** doit ajouter une instance de la structure **match** à la slice **self.matchRecord**. * L'appel de la fonction membre **addMatch** doit se trouver dans la fonction membre **Fight**. * Ajoutez un paramètre boléen à la fonction membre **Greeting**. ```go= func (self Wizard) Greeting(fullGreeting bool) ``` * Si le paramètre **fullGreeting** est égal à **True** alors nous devons, en plus du message de Greeting précédent, afficher tout notre historique de match. * > On my match number #0 I've faced Harry Pointer and I have lost... * > On my match number #1 I've faced Ron OuiOui and I have won ! #### Exemple de main et de résultat : >main.go ```go= package main import ( "hello/poudlard" ) func main() { var harry poudlard.Wizard harry = poudlard.CreateWizard("Harry Pointer", "Je suis l'elu, ron.", 10) harry.Greeting(false) ron := poudlard.CreateWizard("Ron Ouioui", "je suis l'ami de l'elu", 5) poudlard.WizardMatch(&ron, &harry) ron.Greeting(true) harry.Greeting(true) } ``` > Objectif: ![](https://i.imgur.com/8DTbZAm.png) ### TP: Load and Save L'objectif est de créer deux fonctions membres qui vont "sauvegarder" l'historique de notre sorcier favori dans un fichier json. * Créez la fonction membre Save ```go= func (self *Wizard) Save() (error) { } ``` * La fonction devra transformer **self.matchRecord** en texte json grâce au package **"encoding/json"** * La fonction devra également écrire ce texte json dans un fichier nommée "NomDuSorcier.json" * > ex: Harry Pointeur.json * Créez la fonction membre Load ```go= func (self *Wizard) Load(name string) (error) { } ``` * La fonction lira le contenu du fichier correspondant au nom du sorcier passé comme argument. > .Load("Harry Pointer") => Reading "Harry Pointer.json" * La fonction transposera le json lu dans le fichier avec sa variable membre **self.matchRecord** grâce au package **"encoding/json"**. * Finalement, la fonction affichera le nombre de matchs présents dans l'historique du sorcier. #### Exemple de main et de résultat : >main.go ```go= package main import ( "hello/poudlard" "fmt" ) func main() { var harry poudlard.Wizard harry = poudlard.CreateWizard("Harry Pointer", "Je suis l'elu, ron.", 10) ron := poudlard.CreateWizard("Ron Ouioui", "je suis l'ami de l'elu", 5) poudlard.WizardMatch(&ron, &harry) poudlard.WizardMatch(&ron, &harry) harry.Greeting(true) err := harry.Save() if err == nil { fmt.Println("Saved !") } gilbert := poudlard.CreateWizard("Gilbert mytho", "j'etait l'elu, moi aussi.", 1) gilbert.Load("Harry Pointer") gilbert.Greeting(true) } ``` >Objectif: ![](https://i.imgur.com/reCmIcx.png) #### *Tips*: ##### Comment écrire et lire dans un fichier : ```go= import ( "io/outil" ) func exemple () error { // Returning an error err = ioutil.WriteFile("something.txt", data, 0644) // data est un []byte, pour obtenir une chaines de caractère => string(data) if err != nil { fmt.Println("WriteFile Failed with error : ", err) return err } data, err := ioutil.ReadFile("something.txt") if err != nil { fmt.Println("ReadFile failed with error: ", err) return err } return nil // Retourner nil vient à annoncer que tout c'est bien passer. } ``` ##### Comment utiliser le format json en Golang : https://gobyexample.com/json ### TP: Cat(1) --- **File:** cat.go **About:** os and io. **Compilation:** go build || go run Écrire une version simplifiée de la commande cat(1). Votre exécutable doit prendre un ou plusieurs fichiers comme paramètres, et n'a pas besoin de gérer le cas particulier de l'entrée standard. En cas d'erreur (fichier introuvable, autorisation refusée, etc.), vous devez écrire le message suivant dans la sortie d'erreur : ```bash my_cat : < file >: No such file or directory ``` < file > doit être remplacé par le nom du fichier pour lequel l'erreur s'est produite. Si aucun paramètre n'est passé à votre programme, vous devez écrire le message suivant sur la sortie standard : ```bash my_cat : Usage : ./ my_cat file [...] ``` #### *Tips*: https://gobyexample.com/command-line-arguments