Golang Introduction [FR] - Gists · GitHub
Maybe your like
Cours langage GO - annotation - Anthony Le Goff
#INTRO ALGORITHME SOUS GO De l'écriture du premier programme à la logique informatique golang
http://golang.org
Premier programme et présentation de "hello world"
code hello.go
package main import "fmt" // Implémentation formatage I/O module package main /* Début du bloc avec accolade fonction main afficher qqchose */ func main() { fmt.Printf("Hello, chrome os\n have fun こんにちは世界\n") }Installation
sous UNIX Shell (crosh exemple après shell access mode développeur)
- Télécharger la dernière version sur le site golang. Linux amd64 et extraire l'archive tar.gz [gzip] avec la commande tar -xzf <fichier.tar.gz>
-xzf est le flag de la commande tar, plus d'information shell tar --help
Vous pouvez faire le téléchargement en ligne de commande via
wget url/fichier.tar.gzVérifier le hashage de l'archive, si les données ne sont pas corrompu durant le téléchargement algorithme cryptographique sha1 .
sha1sum fichier.tar.gzLa suite de chiffre / lettre doit correspondre avec le lien sur le site / server
Enfin décompresser l'archive dans /usr/local via la commande
sudo tar -C /usr/local -xzf ~/Downloads/<fichier>.tar.gzUne fois installer en lançant /usr/local/go/bin/go accès aide cmd go
-
Créer dossier de travail gocode inclus dossier bin pour binaire et src pour code source. Ce positionner dans dossier travail avec la commande cd
-
Configurer Gopath
Gopath permet de gérer la persistance redémarrage et la gestion package et de les installer dans le système. Via éditeur ligne de cmd nano ou vi:
$ vi ~/.bashrcAjoutez en mode insertion vim en tapant i
export PATH=$PATH:/usr/local/go/bin export GOPATH=~/Downloads/gocode export PATH=$PATH:$GOPATH/bin sudo mount -i -o remount,exec /home/chronos/user/Sauvegardez et quitter le fichier en lançant échap et cmd :wq! sous vim
Redémarrer ou taper ces 4 lignes commandes dans le shell prise en compte immédiate
- Compile et test dans src via go build hello.go puis ./hello
- Installer package créer le dossier dans src puis go install hello & lancer en faisant hello
Introduction
La programmation en GO est un langage informatique développé à l'origine par Robert Griesemer, Rob Pike, Ken Thompson, Ian Taylor, Google en 2007. Le public qui est familiarisé avec certain type de langage tels que:
- C
- C++
- Perl
- Java
- Erlang
- Scala
- Haskel
Aurons moins de mal à appréhender la programmation Go dont il est inspiré. Ex: Docker est un programme jeune et populaire développé en Go sous Github. Go est un langage orienté pour "systèmes et les réseaux" prisé par le C & C++ . Cela n'empêche pas de développer en Go web server ou encore apps smartphone. Il est possible de trouver bien de la documentation en Go sur le site officiel à l'adresse http://golang.org/doc/ Egalement la documentation spécifique est disponible sous un programme nommé godoc exemple d'utilisation avec les opérateurs et les fonctions built-in:
% godoc builtin /*ou en local dand le navigateur via shell:*/ % godoc -http=":6060" /*Puis dans la barre du navigateur:*/ http://localhost:6060/pkg/builtinGo est-il un langage orienté-objet? Oui et non à la fois, Go introduit la notion d'interface qui est un ensemble de méthodes, une fonction peut être attachée à un type, ou encore l'héritage multiple ainsi que pour définir une structure de Tache grâce au constructeur.
Clair et Simple Go à pour but en quelques lignes de code de pouvoir faire beaucoup de chose
Concurrent Go permet de parallelisé des taches à l'intérieur d'espace d'adressage, à travers des processus et des coeurs multiple de processeur grâce au goroutine
Canaux La communication à travers des Goroutines est faîte via canal
Rapidité La compilation est rapide, plus rapide que la compilation en C mesuré en Seconde.
Format standard La règle est simple, la sortie du filtre gofmt est le format officiel
Type postfix Le Type est donnée après le nom variable comme var a int au lieu de int a; comme on retrouve en C.
UTF-8 UTF-8 est partout, dans les strings et le code. Final il est possible utiliser dans le code source Φ = Φ + 1
Open Source La licence Go est entièrement open source, voir le fichier LICENSE dans le code source de la distribution Go.
Définition Algorithme
La langage Go est abordé en parallèle à introduire l'algorithme informatique au niveau des notes prise pour le lecteur. L’algorithmique est l’ensemble des règles et des techniques qui sont impliquées dans la définition et la conception d’algorithmes, c’est-à-dire de processus systématiques de résolution d’un problème permettant de décrire les étapes vers le résultat. En d’autres termes, un algorithme est une suite finie et non-ambiguë d’instructions permettant de donner la réponse à un problème.
L’information est la matière première de l’informatique . Les algorithmes, qui sont constitués d’informations, stockent, manipulent et transforment d’autres informations, à l’aide de machines traité sous forme de programme avec son code source. Tout, en informatique, est représenté comme une séquence de 0 et de 1 : les algorithmes, ou plutôt les programmes,le contenu d’un livre, une photo, une vidéo...
Vous avez dit binaire?
La base binaire est le langage machine, il ne comprend que des suites de 001011 il y a une raison théorique et technique de l'utilisation du binaire:
- On ne peut pas faire plus simple que 2 symboles (0, 1) avec un symbole plus rien ne fonctionne
- Les symboles 0 et 1 sont transposables électroniquement par: le courant passe ou ne passe pas. Réprésente donc toutes les informations sous forme de bits ( binary digit = chiffre binaire). La quantité d'information est justement le nombre de bit nécessaires pour représenter cette information.
- Le stockage de l'information binaire progresse niveau technique et l'utilisation du Qbit comme base computation ou le spin de l'électron dans la théorie quantique est "up" = 1 ou "down" = 0 ou l'Etat du système admet une information intriquée.
Base et unité
- Le bit (binary digit) est l'unité d'information: par 0 ou 1
- L'octet est un groupe de 8 bits (octet en anglais = bytes)
La mémoire (disque dur, mémoire flash...) sa taille est indiqué en système SI internationnal multiplicateur 10³ (symbole k,M,G,T pour kilos, Mega, Giga et Tera) et pour les multiplicateurs 2¹⁰ etc symbole Ki, Mi, Gi,etc pour kibi, mébi et gibi particulièrement en informatique. Base 2.
Les bases ont retrouve plusieurs familles et conversion en informatique:
- Décimale base 10 (0,1,2,3,4,5,6,7,8,9)
- Binaire base 2
- Hexadécimal base 16 (0,1,2...A,B,C,D,E,F)
La théorie systémique
Point a abordé et la notion de machine introduit par la cybernétique et englobant un domaine bien plus large tels que la théorie des systèmes commencé année 1950 avec von bertalanffy sur les systèmes biologiques. Trois directions:
- Le systémisme qui apporte le principe de complexité
- Un autre systémisme abordé sur quelques choses de plus vague, sur quelques vérité holistiques sans devenir opérantes (ni réelle, ni formel, ambigu & fantome)
- Il y a le system analysis qui est le correspondant systémique de l'engineering cybernétique en opération réductrice mais transdisciplinaire.
La théorie des constructeurs
La programmation évolue et l'on voit l'accès à l'informatique quantique grand public. Dans cet évolution une théorie de l'information quantique a évolué de l'information classique et l'avènement de l'utilisation du Qbit quantum-bits. Le caclcul quantique via RF SQUID et l'information quantique appartient notion de super-information, de paires d'attributs non discernables. Il y a impredictibilité de processus déterministes. La cohérence de la paire d'attribut admet une information localement inaccessible.
Pour plus d'information sur la programmation informatique quantique un détour sur le langage Quipper.
Variables, Types et mot-clés
Pour introduire les bases et les types petit rappel sur l'entier et sa définition par la variable int
Type int >>> 2009 # décimal 2009 >>> 0b11111011001 # binaire 2009 >>> 0o3731 # octal 2009 >>> 0x7d9 # hexadecimal 2009Important que de ce rappeler que les bases ont un préfixe 0b, Oo, 0x
En langage Go la syntaxe ce réfère énormément au langage C avec un point qui rend fou les codeurs pour débuggué le programme: la fin du ";" et le calvaire trouver celui qui était manquant dans le programme le rendant impossible à compiler. La différence majeur au niveau des variables par rapport aux autres langages, elle est specifié après le nom variable tels que:
Pas int a, mais plutôt a intDonc après var a int sa valeur assigné est de 0. Avec var s string la valeur zéro de la string vaut "". Déclaré et assigné en Go est deux process.
Déclaration avec =
var a int var b bool a = 15 b = falseDéclaration avec :=
a := 15 b := falseL'utilisation de := est essentiellement pour les variables déclarés dans les fonctions. Multiple déclaration de variable peuvent être groupé et const & import autorise cela. Ecriture:
var ( x int b bool )Multiple variable peuvent être assigné sur une ligne également:var x,y int Ou encore un assignement en parallèle:
a, b := 20, 16Les booléens sont de type bool et prennent la valeur de test de condition tout ou rien "TOR" true ou false Les variables numériques, il faut prendre en compte le cas des virgules flottantes. La déclaration de nombre réel à virgule flottante ce fait de cet manière soit en float32 ou float64 au niveau du type au besoin de l'architecture.
// déclaration de la constante Pi const Pi = 3.14159 // déclaration variable rayon en virgule flottante var rayon float32 = 1.0Chaine de caractère Strings
L'un des principaux buit-in type est string. Affectation valeur chaine de caractère ce fait de cet façon rapide s := "Hello World!". En Go string prend une valeur d'encodage en UTF-8 entre double citation. Un petit exemple pour changer la première valeur de la string "Hello World" en Go.
s := "hello World" c := []rune(s) c[0] = 'c' s2 := string(c) fmt.Printf("%s\n", s2)Explication:
- Converti s en une array de runes
- Change le premier élement de cet array
- Créer une nouvelle string s2 avec modification
- Enfin print la valeur de la string dans fmt.Printf
Multiple string
Ecrire des strings et assemblage sur plusieurs lignes:
s := "Starting part" + "Ending part" // OU utilisant raw string et (`) s := `Starting part Ending part`Runes
Rune est un alias pour int32 encodé en UTF-8. Permet d'instancer, itération de caractère de string. Possible de faire loop sur chaque octets. Problème encodage string en 8-bit ASCII ne sont pas intégré en Go.
Nombres complexes
Go a en natif le support des nombres complexes sans librairies. Le type de variable est nommé complex128(64 bit réel et partie imaginaire) ou complex64 (32 bit réel et partie imaginaire). Règle:
var c complex64 = 5+5i;fmt.Printf("Value is: %v", c) // %v défault format valeur /* Après compilation et lancement */ print: (5+5i)Complexe écrit comme re + imi ou re est partie réel et im imaginaire
Errors
Dans des programmes il est nécessaire de reporter des erreurs, le built-in Go permettant cela s'appel error et ce déclare var e error valeur 'nil'. Ce type est une interface.
Opérateur et fonction built-in
Opérateur arithmétique
20 + 3 # 23 20 - 3 # 17 20 * 3 # 60 20 / 3 # 6.666666666666667 20 % 3 # 2 (modulo) abs(3 - 20) # valeur absolueType booléen
Deux valeurs possibles : False, True. • Opérateurs de comparaison : == (egal), != (strict different), >, >=, < et <= : 2 > 8 # False 2 <= 8 < 15 # True /*Cette optimisation est appelée « principe du shortcut »*/ (3 == 3) || (9 > 24) # True (dès le premier membre) (9 > 24) && (3 == 3) # False (dès le premier membre) /* Opérateurs logiques */ && ET logique, || OU logique, ! négation logiqueOpérateur bit à bit
& ET logique bit à bit, | OU logique bit à bit, ^ OU EXCLUSIF bit à bit, ~ complément binaire ou négation bit à bit, /* opérateurs il faut ajouter*/ << décalage binaire à gauche >> décalage binaire à droiteAlgorithme d'Euclide
L’algorithmique est bien plus ancienne que l’informatique, que l’ordinateur, et que le langage Go, utilisé dans ces notes. Les exemples les plus anciens et célèbres sont :
- les calculs d’impôts Babyloniens (il y a 4000 ans)
- le calcul du plus grand diviseur commun (Euclide, vers −350)
- les première méthodes de résolution systématique d’équations (Al Khawarizmi, ixe siècle)
Les algorithmes étaient donc d’abord utilisés «à la main». Aujourd’hui on entend généralement par algorithmique la réflexion préliminaire à l’écriture d’un programme d’ordinateur, c’est à dire la recherche d’une méthode systématique et non ambiguë pour résoudre un problème. C’est la partie conceptuelle de la programmation, l’abstraction 1 d’un programme d’ordinateur. L’algorithmique est parfois considérée comme une branche des mathématiques, parfois comme une branche de l’informatique. Les notions d’algorithme, puis d’ordinateur ont été formalisées dans les années 30 et 40 par : Kurt Gödel, Alan Turing, John von Neumann... Avoir des notions en algorithmique permet de développer soi-même des programmes, et/ou d’avoir une discussion constructive avec une équipe de développeurs. Les compétences en algorithmique font aussi partie du bagage minimum d’un scientifique, qu’il soit technicien, chercheur, ingénieur ou simplement curieux.
Ecriture exemple Algorithme d'Euclide
Étant donnés deux entiers, retrancher le plus petit au plus grand et recommencer jusqu’à ce que les deux nombres soient égaux. La valeur obtenue est le plus grand diviseur commun.
Dans cet idée, on introduit le principe des structures de controle c-a-d on repart sur la base si et sinon [if, else] permettant de faire des boucles. Le while équivaut à "répéter" en français disparait en langage Go au profit de for et switch
/* ---------------------- | ALGORITHME EUCLIDE | ---------------------- E1: Formuler l'idée ___________________ Étant donnés deux entiers, retrancher le plus petit au plus grand et recommencer jusqu’à ce que les deux nombres soient égaux. La valeur obtenue est le plus grand diviseur commun. E2: Décrire étapes __________________ a,b : deux nombres Répéter tant que a et b sont différents : si le plus grand est a : les deux nombres deviennent a−b et b sinon (b est donc le plus grand) : les deux nombres deviennent a et b−a le pgcd est a Les espaces equivaut à l'indentation, ici = 4 (test et répétition de tâche) E3: Algorithme formel _____________________ fonction pgdc(a,b : entiers) repeter tant que a/=b si a>b a=a−b sinon b=b−a retourner a On retrouve premières bases algo avec les boucles (while) et test de condition (if, else) Notons que en Go While n'existe pas. Il faut donc remplacer par une boucle for et l'accolade = retourner a --------------------------------------- */ /* E4: Ecriture programme principale calcul plus grand dénominateur commun */ package main import "fmt" func main() { a := 933 b := 789 for a != b { if a > b { a = a - b } else { b = b - a } } fmt.Println("le PGDC vaut", a,":", b) }La valeur retourner de votre programme après compilation et édition: Sauvegarder pgdc.go puis dans le dossier de travail lancer go build pgdc.go enfin pour lancer l'executable bin taper shell ./pgdc
Valeur de sortie: le PGDC vaut 3 : 3
Dans ce programme nous avions déclaré deux entiers a = 933 et b = 789. Le plus petit diviseur commun valant donc 3 par l'analyse algorithmique d'Euclide. La difficulté ici resulte à print via un Println de fmt. Cett fonction formate de manière auto tout type paramètre. Retourne la chaine formatée au lieu de l'afficher équivaut à utiliser formatage défaut %v. Le formatage de texte est le module fmt.
Programmer est l’activité qui consiste à :
- traduire des algorithmes dans un langage de programmation :
- afin d’obtenir des réponses effectives (souvent numériques) à des problèmes ;
- afin de se distraire...
- corriger des erreurs dans un programme ;
- rester calme...
Pour aller plus loin l'idéal programme pouvoir insérer une valeur d'entrée à a & b par l'utilisateur et comparer nombres déterminant un pgdc. Non appliqué dans l'exemple mais scanf du module fmt et l'opérateur & le font.
Il est courant d'utiliser controle d'état return ou break à la fin tels que:
if err := Chmod(0664); err != nil { // nil is like C’s NULL fmt.Printf(err) // erreur limité au corps du if return err }On peut utiliser les opérateurs logiques dans les structures de contrôle:
if true && true { fmt.Println("true") } if ! false { fmt.Println("true") }GOTO
GO utilise le goto permet de sauter à un label prédifini dans la fonction courante tels que pour un loop:
func myfunc() { i := 0 Here: // label du goto LOOP println(i) i++ // iterateur compteur incrémentation goto Here // Jump }La boucle For
En langage Go le for s'utilise sous 3 formes:
for init; condition; post { } // Comme en C for for condition { } // Comme un while for { } // boucle infiniExample sous l'écriture en C for en Go et incrementation compteur
sum := 0 for i := 0; i < 10; i++ { // init; condition; post sum += i // reduction écriture de sum = sum + i } // i cesse d'exister à la fin de la boucleLe mot-clé range
Range s'utilise dans le cadre d'un loop pour slices (tranches), arrays (tableau), strings, maps, et canaux. range est un itérateur qui appel paire de clé. Quand il boucle sur slice ou array, il retourne l'index dans le slice comme une clé et sa valeur.
Switch
Go mot-clé switch est flexible. Pas besoin de constante ou entiers, c'est un comparateur de valeur via le mot-clé case et default simplifie:
if i == 0 { fmt.Println("Zero") } else if i == 1 { fmt.Println("One") } else if i == 2 { fmt.Println("Two") } else if i == 3 { fmt.Println("Three") } else if i == 4 { fmt.Println("Four") } else if i == 5 { fmt.Println("Five") }Ce programme indique le nom anglais associé à un nombre via switch cela donne
switch i { case 0: fmt.Println("Zero") case 1: fmt.Println("One") case 2: fmt.Println("Two") case 3: fmt.Println("Three") case 4: fmt.Println("Four") case 5: fmt.Println("Five") default: fmt.Println("Unknown Number") }Fonctions built-in
Les built-in sont des fonctions inclus sans besoin de faire appel à des librairies ou des packages.
- close utilisé canal de communication, ferme un canal
- delete utilisé pour supprimer entrée maps
- len & cap sont utilisés pour retourner longueur d'un string ou tableau et d'un slice
- new permet d'allouer de la mémoire pour utilisateur défini types données
- ** make** Utiliser allouer mémoire built-in types (maps, slices, canaux)
- copy permet de copier un slice
- ** append** concaténation de slice
- panic, recover comme mécanisme d'exeption
- print, println fonction d'impression bas niveau sans "fmt" debugging
- complex, real, imag utilisation des nombres complexes
Tableaux, Slices et maps
Un tableau array de valeurs est une série consécutive de valeurs, accessibles par leur indice entier, 0,1,2,3... En Go on déclare un tableau en faisant précéder le type des éléments par la taille en crochets var x [5]int donc x nom du tableau composé de 5 entiers. Test de programme tableau
package main import "fmt" func main() { var x [5]int x[4] = 100 // Allouer 100 à l'élément 4 du tableau fmt.Println(x) }Afficher valeur print
[0 0 0 0 100]
Un tableau commence toujours par la valeur 0,1,2,3,4..... Zéro est inclus
Calcul de moyenne
Ici nous allons abordé les tableaux par le calcul de la somme arithmétique de valeur pour diviser par le nombre de valeur, équivaut nombre élément dans le tableau.
package main import "fmt" func main() { var x [5]float64 x[0] = 17.5 x[1] = 11 x[2] = 9 x[3] = 14.5 x[4] = 13 var total float64 = 0 for i := 0; i < 5; i++ { total += x[i] // Incrémente les valeurs du tableau x sur chaque élément } fmt.Println(total / 5) // Total sur le nombre de valeur }Quelques explications sur l'utilisation du tableau
- On déclare un tableau de 5 élément en virgule flottante
- Allocation pour chaque élément une valeur = nos notes
- Déclare variable total en virgule flottante entière
- Boucle for et init, condition, post (incrémente supérieur)
- Calcul bloucle for total incrémenté à chaque élément du tableau x
- Println du total divisé par 5 (nombre de valeur)
A partir de cet compréhension du tableau, on va amélioré le code de manière plus réduite (less is more) en place et optimiser le calcul de valeur moyenne. Nouveau programme
package main import "fmt" func main() { xs := []float64{17.5,11,9,14.5,13} // composite literale total := 0.0 for _, v := range xs { total += v } fmt.Println(total / float64(len(xs))) }- On découvre une nouvelle manière d'interprété un tableau sur une ligne
- Une boucle for "_" (underscore) à la place "i" car non appelé itérateur + range
- Conversion tableau défaut int println en float64 sur un len équivaut taille du tableau
Slices
Un Slice est un seqment d'un tableau array qui est indexable et a une longueur.
slice != array la longueur est autorisé à changer pour le slice
Prenons l'exemple var x []float64 entre crochet valeur longueur prend 0 La taille du tableau est fixe sur une valeur [] donc créé un slice pour le modifier en utilisant le built-in make
x := make([]float64, 5)Il y a un troisième paramètre. Correspond à la capacité du tableau dont le slice pointe.
x := make([]float64, 5, 10)Dans cet exemple len(x) = 5 et cap(x) = 10 La règle qui différencie Array & Slice est donc que:
len(slice)== n ; cap(slice)== m ; len(array)== cap(array)== m .Une autre manière de créer un slice est en utilisant expression [low : high]
arr := []float64{1,2,3,4,5} x := arr[1:4]Même si le tableau a 5 élément, notre slice défini [1:4] retourne [2,3,4] Ainsi arr[0:] équivaut à arr[0:len(arr)] et arr[:5] correspond à arr[0:5]
Copy & append
Si vous avez besoin d'étendre un slice il y a des built-in fait pour ça tels que append & copy. Append alloue un nouveau slice dans le slice éxistant
s0 := []int{0, 0} s1 := append(s0, 2) s2 := append(s1, 3, 4, 5, 7) s3 := append(s2, s0...) // Noter 3 petits pointss3 retourne s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
La fonction copy éléments de slice d'une source src à la destination dst et retourne le nombre d'élément copié.
var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7} var s = make([]int, 6) n1 := copy(s, a[0:]) // n1 == 6,s == []int{0, 1, 2, 3, 4, 5} n2 := copy(s, s[2:])Le type map ce retrouve dans plusieurs langage. En C++ c'est la même chose, en Perl on trouve hashes et en Python les dictionnaires. Map est une collection de paire de clé en désordre. Notion de clé associée. Prenons exemple x["clé"] = 10 et supprimons la valeur de la clé.
x := make(map[int]int) x[1] = 10 fmt.Println(x[1])Quand on Print la valeur de clé "1" on obtient 10. Et pour supprimer la clé:
delete(x,1)Tableau d'élement périodique en chimie et le type map comme exemple dans un programme. 10 élément chimique indexe leur symbole. Print sur la clé "Li" qui affiche sa valeur Lithium
package main import "fmt" func main() { elements := make(map[string]string) elements["H"] = "Hydrogen" elements["He"] = "Helium" elements["Li"] = "Lithium" elements["Be"] = "Beryllium" elements["B"] = "Boron" elements["C"] = "Carbon" elements["N"] = "Nitrogen" elements["O"] = "Oxygen" elements["F"] = "Fluorine" elements["Ne"] = "Neon" fmt.Println(elements["C"]) }On peut raccourcir et simplifier le code de cet manière sur type map
elements := map[string]string{ "H": "Hydrogen", }Cela permet d'une manière général de stocker de l'information. Ajoutons à la paire de clé et valeur une autre entrée tels que quelques terres rares
func main() { LREE := map[string]map[string]string{ "Y": map[string]string{ "Nom":"Yttrium", "Numéro et masse atomique":"N°39 et ma 88.90", }, "Nd": map[string]string{ "Nom":"Neodyme", "Numéro et masse atomique":"N°60 et ma 144.24", }, "Eu": map[string]string{ "Nom":"Europium", "Numéro et masse atomique":"N°63 et ma 151.25", }, "Dy": map[string]string{ "Nom":"Dysprosium", "Numéro et masse atomique":"N°66 et ma 162.50", }, } if el, ok := LREE["Y"]; ok { fmt.Println(el["Nom"], el["Numéro et masse atomique"]) } }Le if est utilisé pour indéxer une recherche dans le tableau à travers une valeur de clé et print ces valeurs: test d'existence
Note sur la complexité la recherche dans map (dictionnaire) en fonction nombre de valeur à indéxer admettent un temps de performance des algorithmes. Ainsi dans la recherche dichotomique, l'algorithme en Θ(log(n)) ou logarithmique est à préviligié dans l'écriture de boucle de fonction.
Exercices
Développement selon John Zelle
Analysez le problème Comprenez le problème à résoudre et sa nature. Essayez d’en apprendre le plus possible sur lui. Vous ne pourrez pas le résoudre avant de le connaître parfaitement.
Spécifiez le programme Décrivez très exactement ce que votre programme va faire. Vous ne devez pas déjà vous soucier de la façon dont il va le faire, mais plutôt décider très exactement ce qu’il va faire. Pour des programmes simples, cela consistera à décrire ce que seront les entrées et les sorties du programme et ce qui les relie.
Concevez le programme Formulez la structure globale du programme. C’est à ce moment que vous traiterez de la façon dont le programme résoudra le problème. Le travail principal est de concevoir le ou les algorithmes qui rempliront les tâches préalablement spécifiées.
Codez Traduisez les algorithmes conçus dans un langage de programmation et entrez les sur un ordinateur. Dans ces notes, nous programmerons nos algorithmes en Go.
Testez/Débuggez le programme Essayez votre programme et voyez s’il fonctionne comme vous le souhaitiez. S’il y a des erreurs (souvent appelées bugs), revenez à l’étape précédente et corrigez les. L’activité qui consiste à débusquer et corriger les erreurs s’appelle le debuggage. Durant cette phase, votre objectif est de trouver des erreurs, et pour cela, vous devez tester tout ce qui vous passe par le tête et qui pourrait planter le programme. Il sera utile de garder à l’esprit la maxime :
Nothing is foolproof because fools are too ingenious
Faites de la maintenance Continuez à développer votre programme en répondant aux besoins des utilisateurs. La plupart des programmes ne sont jamais vraiment finis ; ils continuent d’évoluer au fil des années d’utilisation.
Calcul de puissance et Entrée[Input] / Sortie[Output]
Q1. On va partir sur un programme simple mathématique sur les puissances pour introduire la saisie utilisateur. L'idée du programme est de connaitre une valeur de la fonction inverse 1/r² ou r est défini par l'utilisateur en début de programme. Pour plus d'information sur la fonction 'input'
godoc fmtRechercher func scanf et utilisation de l'opérateur & pour trouver adresse de variable
A1. Solution au problème
package main import "fmt" func main() { fmt.Print("Entrée un nombre: ") var r float64 fmt.Scanf("%f", &r) // %f précision pour virgule flottante x := 1 / ( r * r ) fmt.Println("Valeur inverse² :", x) }Runes: Comptage de symbole strings
Q2. Un nouveau problème de poser et les chaines de caractère. Admettons une énigme cryptographique sous un langage inconnu de symbole. On ne sait pas ce que cela veut dire, mais on aimerait bien compter le nombre de caractère de la chaine. Et en addition compter le nombre d'Octet de la string via module "utf8" voir godoc unicode/utf8 chaine à analyser: ⢎𝚿⣟ ⣹𝚲⢪ ⢱𝚵⢧
A2. Solution pour compter des runes et des octets. En cherchant dans godoc et utf8 on trouve une fonction qui permet de compter les runes func RuneCount(p []byte)int Pour convertir string vers octets
str := "hello" b := []byte(str)On ce retrouve donc avec ce programme runes_count.go
package main import ( "fmt" "unicode/utf8" ) func main() { str := "⢎𝚿⣟ ⣹𝚲⢪ ⢱𝚵⢧" fmt.Printf("String %s\nLength: %d, Runes: %d\n", str, len([]byte(str)), utf8.RuneCount([]byte(str))) }Valeurs affichées
String ⢎𝚿⣟ ⣹𝚲⢪ ⢱𝚵⢧
Length: 32, Runes: 11
Quelques explications sur le formatage de texte de la fonction printf et l'opérateur %
- suivi d'un “d”, il implique la présence d'un entier et le formate en décimal,
- suivi d'un “s”, il implique la présence d'une chaîne,
- suivi d'un “x”, il implique la présence d'un entier et le formate en hexadécimal,
- suivi d'un “g”, il implique la présence d'un réel,
- suivi d'un “v”, il formate de manière automatique n'importe quel type,
- suivi d'un “T”, il affiche le type de la valeur fournie
- \n renvoi à la ligne
D'ou
- %s renvoi à str
- premier %d renvoi à len([]byte(str))
- second %d renvoi à utf8.RuneCount([]byte(str))
Q3. Enfin de compte les symboles cryptés on peut y insérer d'autre chaine de caractère à l'intérieur. Remplacer dans la chaine ⢎𝚿⣟ ⣹ ⢱𝚵⢧ ⣾𝛀⣀ ⣒𝚹⢕ à la position 10, 3 runes par ⣹𝚲⢪
A3. runes-copy.go
package main import "fmt" func main() { s := "⢎𝚿⣟ ⣹ ⢱𝚵⢧ ⣾𝛀⣀ ⣒𝚹⢕" r := []rune(s) copy(r[10:10+3], []rune("⣹𝚲⢪")) fmt.Printf("Script symbole original : %s\n", s); fmt.Printf("Modification symbolique : %s\n", string(r)) }Q4. La personne faisant de la rétro-ingénierie sur cette série de symbole codé a remarqué qu'il était possible d'obtenir quelque chose de différent en inversant le string. Après tout cela dépend du sens que nous écrivons que nous faisons la compréhension d'un langage! Alors inversé la chaine ⢎𝚿⣟ ⣹ ⢱𝚵⢧ ⣹𝚲⢪ ⣒𝚹⢕
A4. programme reverse.go
package main import "fmt" func main() { s := "⢎𝚿⣟ ⣹ ⢱𝚵⢧ ⣹𝚲⢪ ⣒𝚹⢕" a := []rune(s) // Une conversion for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { a[i], a[j] = a[j], a[i] // Assignement parallele } fmt.Printf("%s\n", string(a)) // Retour converti }Fonctions
Une fonction est une section indépendante de code qui maps zéro ou plusieurs paramètres d'entrées INPUT. Les fonctions sont également appelés procédures ou des subroutines. Les fonctions sont représenté par une boite noire ou un code est exécuté par la fonction. Noire car par exemple une voiture est une boite noire pour son utilisateur: Il appuie sur l'accélérateur INPUT et en sortie le véhicule ce déplace OUTPUT. Ce ne veut pas dire que vous savez comment marche le moteur et tout le processus mécanique derrière. D'ou concept de boite noire.
Les notions de boite noire et boite blanche sont très importante pour résoudre des niveaux d'abtraction et d'isolation de système, utilisé définir architecture ou encore en notation UML
Sur nos programmes Go nous utilisons seulement auparavant une fonction principale func main() {}
Schéma: --------------- INPUT | | OUTPUT ----- > | Boite noire | ----- > | | --------------- // Déclaration de fonction: type mytype int func (p mytype) funcname(q int) (r,s int) { return 0,0 }- func le mot-clé est utilisé pour déclarer une fonction;
- (p mytype) possible de donnée un type specifique appelé receiver dont celui-ci défini la méthode;
- funcname est le nom de votre fonction;
- (q int) est la variable d'entrée et copié dans la fonction pass-by-value;
- (r, s int) sont les paramètres de variable return ;
- { return 0,0 } corps de la fonction entre accolade;
Reprenons l'exemple du calcul de moyenne un peu auparavant pour construire une fonction à partir du main()
func main() { xs := []float64{98,93,77,82,83} total := 0.0 for _, v := range xs { total += v } fmt.Println(total / float64(len(xs))) }La moyenne average d'une série de nombre est un problème classique dans l' algorithminique. Nous allons appeler la fonction average avec un slice en *float64 ainsi qu'un return en float64. On insert le code avant le main()
func average(xs []float64) float64 { panic("Introuvable") }Cela est la signature de la fonction, incluant le paramètre (une liste de nombre) qui est nommé xs et le type return. Le built-in panic appel un erreur runtime, permet de casser le process, routine de la fonction pour debugger plus simplement.
func average(xs []float64) float64 { total := 0.0 for _, v := range xs { total += v } return total / float64(len(xs)) }Ajoutons maintenant l'algorithme dans la fonction
et modification sur le main(), la variable nommé xs pas obligatoire sous même nom.
func main() { xs := []float64{98,93,77,82,83} fmt.Println(average(xs)) }Algorithme récursif
Le paradigme de la programmation fonctionnelle en informatique est important dans la manière d'aborder les itérateurs. On utilise la fonction factorielle de manière récursive, elle suffit à elle même en tant que fonction pour s'appeler.
Factoriel, symbole ! n!= | 1 si n=0 | n(n - 1)! si n >= 1Code go
package main import "fmt" func factorial(x uint) uint { if x == 0 { // cas de base return 1 } // cas récursif return x * factorial(x-1) } func main() { fmt.Println("Valeur vaut: ", factorial(5)) // calcul 5! }Dans cette fonction, la valeur de n! n'est pas connue tant que la condition terminale (ici x == 0) n'est pas atteinte. Le programme empile les appels récursifs jusqu'à atteindre la condition terminale puis dépile les valeurs. Exemple factorial(2)
- Si x == 0? Non. (x vaut 2)
- Trouver le factoriel de x – 1
- Si x == 0? Non. (x vaut 1)
- Trouver le factoriel de x – 1 * Si x == 0? Oui, return 1.
- return 1 * 1
- return 2 * 1
Closure
Il est possible de créer des fonctions à l'intérieur de fonctions
func main() { x := 0 increment := func() int { x++ return x } fmt.Println(increment()) fmt.Println(increment()) }increment ajoute 1 à la variable x défini main() Scope. Cet variable est accessible via fonction increment. Variable est non-local et appelé closure d'ou increment et x forme closure
Variable & Scope
package main var a = 6 func main() { p() q() p() } func p() { println(a) } func q() { a := 9 println(a) }Entre les fonctions et le main() les variables sont local ou global. a := 5 est déclaré dans q() et la valeur Print vaudra : 696
Valeurs de retour multiple
Go utilise le variable return multiple pour une fonction tels que
func f() (int, int) { return 5, 6 } func main() { x, y := f() }Cette notation est utilisé pour connaitre une valeur erreur à coté d'un résultat ou un booléen fonctionnant.
- x, err := f()
- x, ok := f()
Defer, panic & recovering
Go a un état particulier entraine l'éxecution différée d'une commande à la sortie d'une fonction courante. Exemple après avoir ouvert fichier defer fermeture
f, _ := os.Open(filename) defer f.Close()defer est particulièrement utilisé pour libérer des ressources, que cela soit de la mémoire ou des processus.
Lorsque une erreur survient, durant appel de fonction, il vaut mieux indiqué l'erreur par un code return. Mais aussi irréversible qui entraine fin du programme, on appel la fonction panic() et récupéré l'exception lancé via panic avec recover() couplé à defer
package main import "fmt" func main() { defer func() { str := recover() fmt.Println(str) }() panic("PANIC") }Fonctions variadic
Les fonctions variadic en utilisant ... avant le type du dernier paramètre indique prend zéro ou plus paramètres. Tels que Zéro ou plus ints.
func myfunc(arg ...int) {} func add(args ...int) int { total := 0 for _, v := range args { total += v } return total } func main() { fmt.Println(add(1,2,3)) }Exercices
Switch et moyenne arithmétique
Q5. Ecrire une fonction qui calcul moyenne average d'un float64 slice et switch
A5. Code Go average.go
func average(xs []float64) (avg float64) { sum := 0.0 switch len(xs) { case 0: avg = 0 default: for _, v := range xs { sum += v } avg = sum / float64(len(xs)) } return }Paire ou Impaire?
Q6. Exercice sur l'incrémentation. On veut afficher les dix premiers nombres de 1 à 10 et connaitre si ceux-ci sont soit paire ou impaire. Utiliser % modulo
A6. Correction. On retrouve deux structures controle for et if/else et l'incrémentation n+1 ce fait sur la ligne de condition par variable ++
package main import "fmt" func main() { for i := 1; i <= 10; i++ { if i % 2 == 0 { fmt.Println(i, "paire") } else { fmt.Println(i, "impair") } } }Récursion: suite de Fibonacci
Q7. La suite de Fibonacci commence tels que 1,1,2,3,5,8,13... ou en notation mathématique:
| F0 = 0 | F1 = 1 | Fn = Fn−1 + Fn−2 si n > 1Ecrire une fonction prenant le type int donnant plusieurs termes de la suite de Fibonacci.
A7. fi.go
/* Fibonacci sequence */ package main import "fmt" func fibonacci(value int) []int { // variable "value" func, return slice x := make([]int, value) // Init Slice en int et len(value) x[0], x[1] = 0, 1 for n := 2; n < value; n++ { x[n] = x[n-1] + x[n-2] } return x } func main() { for _, term := range fibonacci(11) { // Itérateur range de Fi(11) fmt.Printf("%v ", term) } }Une simple stack LIFO
En informatique la notion de stack empile revient régulièrement, web server, algo.
i | k |<- [i++] --- push(k) | l |pop() -- [i--]-> l 0 | m | Schéma stack LIFO 'last in, first out' Stack de la figure réprésenté par : [0:m] [1:l] [2:k]Q8. Construire une stack LIFO avec un nombre fixe int. Définir push pour mettre quelques chose sur la stack et pop pour enlever de la fonction stack
A8. En premier nous définissons un nouveau type représente stack. Avec une array (gestion clé) et un index. 10 élements dans la stack
type stack struc { // struc permet de construire des types avancés i int data [10]int }Maintenant nous devons créer les fonctions push et pop. En premier défini la solution fausse d'une solution de push et problème pointer.
func (s stack) push(k int) if s.i+1 > 9 { return } s.data[s.i] = k s.i++ }La fonction fonctionne variable s de type stack. En utilisant appel s.push(50) on empile un entier 50 sur a stack. Mais la fonction push a une copie de s et ne fonctionnera pas. Rien n'est empilé sur la stack:
var s stack // s comme stack variable s.push(25) fmt.Printf("stack %v\n", s); s.push(14) fmt.Printf("stack %v\n", s); --- prints: stack [0:0] stack [0:0]Pour résoudre cela on donne à la fonction push un pointer de la stack d'ou:
func (s stack)push(k int) → func (s *stack)push(k int)Pour la création du pointer on fait une allocation avec new() tels que:
s := new(stack)On ce retrouve avec le programme stack.go:
/* Stack LIFO */ package main import "fmt" // Déclare un nouveau type stack, 10 éléments type stack struct { i int data [10]int } // Fonction push sur une stack func (s *stack) push(k int) { s.data[s.i] = k s.i++ } // Fonction pop enlève une stack func (s *stack) pop() int { s.i-- return s.data[s.i] } // Déclaration dans main() variabe s comme stack et push valeur func main() { var s stack s.push(25) s.push(14) fmt.Printf("stack %v\n", s) }Fonction de hashage MD5
Une introduction au algoritme cryptographique et MD5. Retro-ingénierie sur un morceau de code d'une fonction.
/* MD5Hash */ package main import ( "crypto/md5" "fmt" ) func main() { hash := md5.New() bytes := []byte("kenavo\n") hash.Write(bytes) hashValue := hash.Sum(nil) hashSize := hash.Size() for n := 0; n < hashSize; n += 4 { var val uint32 val = uint32(hashValue[n])<<24 + uint32(hashValue[n+1])<<16 + uint32(hashValue[n+2])<<8 + uint32(hashValue[n+3]) fmt.Printf("%x ", val) } fmt.Println() }Q9. Soit ce morceau de code source, comprendre son fonctionnement et définir les différentes étapes en sachant que le print vaut :
22917d0 d14dbfd0 ad38bb8b e1678dc4Algorithme de tri 'sort'
Non trié | 0 | 3 | 12 | -1 | -5 | 5 | Trié | -5 | -1 | 0 | 3 | 5 | 12 |Il fonctionne en répètant des étapes qu'une liste doit être trié, compare chaque paire d'item adjacent et le tri s'il est au mauvais endroit, passe l'étape s'il n'a pas besoin de trier l'item. La fonction s'appelle bubblesort
/* Algorithme formel ----------------- procedure bubbleSort( A : list of sortable items ) do swapped = false for each i in 1 to length(A) - 1 inclusive do: if A[i-1] > A[i] then swap( A[i-1], A[i] ) swapped = true end if end for while swapped end procedure */Q.10 Ecrire la fonction de l'algorithme quadratique complexité en Θ(n ² ) de tri bubblesort
A.10 code bubblesort.go
func main() { n := []int{5, -1, 0, 12, 3, 5} fmt.Printf("unsorted %v\n", n) bubblesort(n) fmt.Printf("sorted %v\n", n) } func bubblesort(n []int) { for i := 0; i < len(n) - 1; i++ { for j := i + 1; j < len(n); j++ { if n[j] < n[i] { n[i], n[j] = n[j], n[i] } } } }Tri par sélection
Une première idée est de procéder ainsi :
- rechercher le plus petit, le mettre au début,
- rechercher le second plus petit, le mettre en deuxième position
- ...
Variadic & var args
Q.11 Ecrire une fonction qui prend un nombre variable int et print chacun d'entre eux sur une ligne séparée.
A.11 On utilise la syntaxe ... qui prend un nombre d'argument au hasard
package main import "fmt" func main() { prtthem(1, 4, 5, 7, 4) prtthem(1, 2, 4) } func prtthem(numbers... int) { // numbers : slice of ints for _, d := range numbers { fmt.Printf("%d\n", d) } }Pointeurs
Définition d'un pointeur
Les pointeurs sont un type important en langage Go. Il s'utilise comme l'adresse pointant une valeur. On peut retrouver la valeur et la modifier avec un pointeur.
Un pointeur est déclaré en faisant précéder le type de donnée pointée par une étoile* (ie: *int // pointeur entier). On prend l'adresse pointant sur une donnée en la faisant précédé opérateur &:
var i = 5 var j *int = &i // pointeur sur iExemple sur ce programme, pointeur référence & mémorise:
Sans pointeur
func zero(x int) { x = 0 } func main() { x := 5 zero(x) fmt.Println(x) // x vaut 5 }Avec pointeur
func zero(xPtr *int) { *xPtr = 0 } func main() { x := 5 zero(&x) fmt.Println(x) // x vaut 0 }Adressage &
L'opérateur & référence à l'adresse du pointeur ainsi il est possible de savoir l'adresse mémoire du pointeur tels que ce code:
var i int // Declare variable entier i p = &i // Faire p pointer vers i fmt.Printf("%v", p) ---- Print 0x7ff96b81c000aLe mot-clé nil
Le mot clé nil représente un pointeur qui ne pointe sur aucune valeur licite. Cela peut représenter la valeur initiale d'un pointeur qui ne pointe vers rien NULL
Allocation
fonction new()
func one(xPtr *int) { *xPtr = 1 } func main() { xPtr := new(int) one(xPtr) fmt.Println(*xPtr) // x is 1 }new prend un argument, alloue de la mémoire pour la valeur du type et retourne au pointeur. Les pointeurs sont utilisé en particulier avec struct le type structuré.
Utilisation de make pour allouer
New() alloues
make() initialises utilisé seulement pour slices, maps, canaux
Exemple
var p *[]int = new([]int) var v []int = make([]int, 100)Retenez
v := make([]int, 100)Constructeur
La définition d'un constructeur est une méthode particulière d'initialisation. Pour plus d'information liser la doc package container/ring et la fonction new défini un constructeur en Go.
Exemple avec le package os
func NewFile(fd int, name string) *File { if fd < 0 { return nil } f := File{fd, name, nil, 0} // Create a new File return &f // Return the address of f }Type structuré
L'idéal serait de construire un programme seulement avec builtin type Go, ce qui arrive pas toujours avec des besoins spécifique de création. Considérer cet exemple intéragi avec des formes:
package main import ("fmt"; "math") func distance(x1, y1, x2, y2 float64) float64 { a := x2 - x1 b := y2 - y1 return math.Sqrt(a*a + b*b) } func rectangleArea(x1, y1, x2, y2 float64) float64 { l := distance(x1, y1, x1, y2) w := distance(x1, y1, x2, y1) return l * w } func circleArea(x, y, r float64) float64 { return math.Pi * r*r } func main() { var rx1, ry1 float64 = 0, 0 var rx2, ry2 float64 = 10, 10 var cx, cy, cr float64 = 0, 0, 5 fmt.Println(rectangleArea(rx1, ry1, rx2, ry2)) fmt.Println(circleArea(cx, cy, cr)) }définir son type avec Struct
Une façon rapide d'optimiser le programme est d'utiliser struct et ces paramètres fields pour définir Circle
type Circle struct { x, y, r float64 }Initialisation
Créer instance type Circle
var c CircleIl est possible également d'utiliser la fonction new() pour struct
c := new(Circle)Cela alloue mémoire pour les fields mise à zéro et un retour pointeur et ainsi redonner une valeur fields tels que:
c := Circle{x: 0, y: 0, r: 5}Fields
On peut accéder aux fields en utilisant l'opérateur .
fmt.Println(c.x, c.y, c.r) c.x = 10 c.y = 5Modifiant function CircleArea avec Circle
func circleArea(c *Circle) float64 { return math.Pi * c.r*c.r }Dans le main()
c := Circle{0, 0, 5} fmt.Println(circleArea(&c))Méthodes
On peut encore écrire la fonction d'une autre manière en utilisant une fonction particulière nommée méthode , dans ce morceau de code on ajoute un receiver permettant d'appeler une fonction utilisant l'opérateur .
func (c *Circle) area() float64 { return math.Pi * c.r*c.r }Dans le print
fmt.Println(c.area())On remarque que l'utilisation des pointeurs en Go en utilisant une méthode à changé. En Go sait automatiquement ajouter un pointeur pour Circle pour cette méthode défini. Change rectangle:
type Rectangle struct { x1, y1, x2, y2 float64 } func (r *Rectangle) area() float64 { l := distance(r.x1, r.y1, r.x1, r.y2) w := distance(r.x1, r.y1, r.x2, r.y1) return l * w }Et dans le Main()
r := Rectangle{0, 0, 10, 10} fmt.Println(r.area())Exercices
Pointeurs
Q.12 . Suppose type structuré est défini:
type Person struc { name string age int }Quel est différence entre ces deux lignes?
var p1 Person p2 := new(Person)Quel est différence entre ces deux allocations?
func Set(t *T) { x = t } and func Set(t T) { x= &t }Map Fonction
func Map(f func(int) int, l []int) []int { j := make([]int, len(l)) for k, v := range l { j[k] = f(v) } return j } func main() { m := []int{1, 3, 4} f := func(i int) int { return i * i } fmt.Printf("%v", (Map(f, m))) }Une map()-function est une fonction attaché à une liste et une fonction tels que:
map(f(),(a1, a2, . . . , an−1, an)) = (f(a1), f(a2), . . . , f(an−1), f(an))
Le code ci-dessus est la solution à l'équation pour le type int
Q.13 Ré-écrire la map-fonction avec une interface générique, en typé int, str
A.13 code map-function-gen.go
package main import "fmt" //* define the empty interface as a type type e interface{} func mult2(f e) e { switch f.(type) { case int: return f.(int) * 2 case string: return f.(string) + f.(string) + f.(string) + f.(string) } return f } func Map(n []e, f func(e) e) []e { m := make([]e, len(n)) for k, v := range n { m[k] = f(v) } return m } func main() { m := []e{1, 2, 3, 4} s := []e{"a", "b", "c", "d"} mf := Map(m, mult2) sf := Map(s, mult2) fmt.Printf("%v\n", mf) fmt.Printf("%v\n", sf) }Interfaces
Une interface est un ensemble de méthodes, c'est à dire des fonctions qu'il est possible d'implémenter pour une type défini. Ce morceau de code défini struct type s avec un field qui défini 2 méthodes pour s
type S struct { i int } func (p *S) Get() int { return p.i } func (p *S) Put(v int) { p.i = v }En définissant type interface I de plusieurs méthodes
type I interface { Get() int Put(int) }Rappeler vous les méthodes communes pour Rectangle & Circle ont area. En définissant une interface nommé Shape:
type Shape interface { area() float64 }L'interface implémenté en langage Go est une forme de duck typing, loin du pure duck typing car la compliation Go va checké statique le type implémenté niveau interface. La conversion checké au moment runtime. Interface est l'idée dans d'autres langages comme pure abstract virtual base classes en C++, typerclasses en Haskell ou duck typing en python.
Aucun langage combine comme en Go : Valeur interface, statique type checking, dynamique runtime conversion, et pas nécessité déclaré qu'un type satisfait une interface.
Concurrent
“Parallelisme est a propos de la performance;Concurrent est à propos du design de programme. Rob Pike”
Quand on code de gros programme informatique il est nécessaire plusieurs sous-programme. L'exemple du web server dans l'attente réponse du navigateur et renvoi à une page HTML en réponse. Chaque requète est comme un sous-programme.
Il serait idéal pour de sous-programme comme ceux-ci de pouvoir les lancer en même temps en parallèle (surtout multiple requète server et de page web) Lancer du multi-tache simultanément s'appel des tâches concurrent. Go est riche dans l'utilisation concurrent avec goroutines et canaux
Goroutines
Une goroutine est une fonction capable de lancer en concurrent d'autres fonctions. Le mot clé pour utiliser une goroutine est go puis l'invocation de fonction.
ready("Green Tea", 2) // Appel fonction normal go ready("Green Tea", 2) ← ready() lancé comme goroutine package main import "fmt" func f(n int) { for i := 0; i < 10; i++ { fmt.Println(n, ":", i) } } func main() { go f(0) // goroutine de f(0) var input string fmt.Scanln(&input) // permet de tout print avant fin de programme et sortir }Ce programme utilise deux goroutines l'une implicite le main() et la seconde à l'appel de go f(0)
Utilisons la fonction time.Sleep pour donner un peu de delay execution tache
package main import ( "fmt" "time" ) func ready(w string, sec int) { time.Sleep(time.Duration(sec) * time.Second) fmt.Println(w, "is ready!") } func main() { go ready("Tea", 2) go ready("Coffee", 1) fmt.Println("I'm waiting") time.Sleep(5 * time.Second) }Dans le même style, il est possible d'éxecuter un temps aléatoire avec la fonction rand
import "math/rand" amt := time.Duration(rand.Intn(250)) // sur un entierAvant de sortir du programme on attend 5 seconde, l'exemple auparavant on demande à l'utilisateur un scanln. On peut fixer le problème en utilisant des canaux
Canaux
Un canal est comparable à un pipeline en UNIX shell. Le type est spécifique au canal. Donc un canal chan permet à deux goroutines go de communiquer en eux et de synchroniser leur execution. Créer canal avec make
ci := make(chan int) // ci integer cs := make(chan string) // cs stringe cf := make(chan interface{}) // cf interfacePour recevoir et envoyer à un canal on utilise l'opérateur <-
ci <- 1 // Envoyer integer 1 vers canal ci <-ci // Recevoir un integer du canal ci i := <-ci // Recevoir du canal ci et le stocker dans iFermer un channel
x, ok = <-ch var c chan int //déclare c variable entier canal func ready(w string, sec int) { time.Sleep(time.Duration(sec) * time.Second) fmt.Println(w, "is ready!") c <- 1 // Envoi integer 1 } func main() { c = make(chan int) // init c go ready("Tea", 2) // lancer goroutine go ready("Coffee", 1) fmt.Println("I'm waiting, but not too long") <-c // Attendre de recevoir du canal 'sans valeur' <-c // Deux goroutines donc deux canaux associer valeur. }select
L'appel select fonctionne comme un switch mais dans l'utilisation d'un canal.
Modification du programme précédent avec select:
var c chan int func ready(w string, sec int) { time.Sleep(time.Duration(sec) * time.Second) fmt.Println(w, "is ready!") c <- 1 // Envoi integer 1 } func main() { c = make(chan int) go ready("Tea", 2) go ready("Coffee", 1) fmt.Println("I'm waiting, but not too long") L: for { select { case <-c: i++ if i > 1 { break L } } } }Parallelisme
Le langage Go utilise goroutine comme concurrent, pour améliorer le parallelisme utiliser la fonction runtime.GOMAXPROCS(n) qui paramètre le nombre maximum de CPU's processeurs utiliser pour lancer simultanément.
Communication
Parlonds rapidement de la communication avec le monde externe. Tels que fichiers, dossiers, réseaux ou éxecuter d'autre programme. GO's I/O avec les interfaces:
io.Reader et io.WriterLire à partir d'un fichier
package main import "os" func main() { buf := make([]byte, 1024) f, _ := os.Open("/etc/passwd") // Ouvrier le fichier defer f.Close() // sur de fermer le fichier for { n, _ := f.Read(buf) // Lecture 1024 octets à la fois if n == 0 { break } // fin fichier os.Stdout.Write(buf[:n]) // écrire contenu vers os.Stdout } }Version buffered
package main import ( "os"; "bufio") func main() { buf := make([]byte, 1024) f, _ := os.Open("/etc/passwd") defer f.Close() r := bufio.NewReader(f) w := bufio.NewWriter(os.Stdout) defer w.Flush() for { n, _ := r.Read(buf) if n == 0 { break } w.Write(buf[0:n]) } }Lancer commands
Le package os/exec a une fonction de lancer des commandes externes. Exemple en lançant la commande UNIX ls -l affichant chaque fichier, information, droit d'accès
Comparaison script shell UNIX et Go création dossier inexistant
Version UNIX Shell ------------------ if [ ! -e name ]; then mkdir name else # error fi Version Go ---------- if f, e := os.Stat("name"); e != nil { os.Mkdir("name", 0755) } else { // error }Packages
Package essentiel en Go
- fmt
- io
- io/ioutil
- bufio
- sort
- strconv
- strings
- math/rand
- os
- sync
- flag
- time
- sync/atomic
- encoding/json
- encoding/gob
- html/template
- net/http
- net/rpc
- unsafe
- runtime
- reflect
- os/exec
- path/filepath
- errors
- container/list
- hash
- crypto/aes
- crypto/md5
Liens vrac
- web toolkit http://www.gorillatoolkit.org/
- Site statique http://gohugo.io/overview/quickstart/ + https://github.com/drone/jkl
- sqlite https://godoc.org/code.google.com/p/go-sqlite/go1/sqlite3
- driver mongoDB noSQL https://labix.org/mgo
- Golang-EN book PDF https://github.com/golang/go/wiki/Books
- Pratique de programmation en Go https://code.google.com/p/golang-france/downloads/list
- Learn https://github.com/gyuho/learn#contents
Tag » Apprendre Golang Pdf
-
[PDF] LE LANGAGE - Dunod
-
Démarrer Avec Le Langage Go
-
[PDF] Programmation En Go/Version Imprimable — Wikilivres
-
Cours Langage Go Pdf
-
Tutoriel Pour Apprendre Le Langage Go Par L'exemple
-
Introduction Du Cours Pour Apprendre Le Langage Programmation GO
-
Apprendre à Coder Avec Le Langage Go En Ligne - Débutant | Skilleos
-
[PDF] Le Langage De Programmation Go - Stéphane Bortzmeyer
-
[PDF] Conseils Pratiques Pour La Rédaction De Programmes Go Maintenables
-
Apprendre Le Langage Go En 2020 | By Jean-Baptiste Le Duigou
-
[PDF] Programmer En Go - Éditions D-BookeR
-
Pratique De La Programmation En Go - PDF Free Download
-
[PDF] Formation-go-golang.pdf - Openska
-
[PDF] Langage Go - Les Fondamentaux - M2i Formation