Go-Language

Learning Go Language

View on GitHub

Carte de référence du langage Go

Sommaire

  1. Bases du langage
    1. Briques du langage
      1. Variable
      2. Constante
      3. Type
      4. Import
      5. Pointeur
    2. Boucle
    3. Instructions de branchement conditionnel
      1. Condition
      2. Switch
    4. Instructions de branchement non conditionnel
      1. Break
    5. Collections
      1. Tableau
      2. Slice
      3. Map
    6. Opérations sur les collections
      1. len()
      2. append()
      3. copy()
      4. delet()
      5. identificateur _
      6. range
    7. Structure
    8. Appels de suites d’opérations
      1. Fonction
      2. Méthode
      3. Interface
    9. Ligne de commande et Arguments
  2. Bibliothèques du langage Go
    1. Principales bibliothèques standards
      1. Bibliothèque fmt
      2. Bibliothèque errors
      3. Bibliothèque os
      4. Bibliothèque io
      5. Bibliothèque strings
      6. Bibliothèque time
    2. Principales bibliothèques tierces
      1. Bibliothèque debug
      2. Bibliothèque mobile
  3. Outils de développement
    1. Présentation
    2. Commandes
    3. Compilation
    4. Tests unitaires
    5. Documentation
  4. Ressources d’apprentissage

Bases du langage

Briques du langage

Variable

Une déclaration permet de créer une variable modifiable à tout moment.

var a int = 1
fmt.Println(a)

// ou directement

b := 1
fmt.Println(b) 

Pour exécuter l’exemple : Playground

Constante

Une constante permet de déclarer un élément non modifiable.

const pi float32 = 3.14

Pour exécuter l’exemple : Playground

Type

Il existe plusieurs types en langage Go :

Les manipulations arithmétiques (+, -, *, /, %, ++ et --), relationnelles (==, !=, >, <, >= et <=) et binaires (<<, >>, &, |, ^) fonctionnent en Go.

import

Le mot clé import permet d’importer des modules tels que les bibliothèques standards (ex : fmt).

import "fmt"

Pour exécuter l’exemple : Playground

Pointeur

Un pointeur permet de faire des références sur des variables. Les pointeurs Go s’utilisent comme en langage C.

func add (val *int){
    *val = *val + 1
}

func main() {
    var cal int = 2
    add(&cal)
    fmt.Println(cal)
}

Pour exécuter l’exemple : Playground

Boucle

Une boucle se fait avec le mot clé for.

for i := 0; i < 10; i++ {
    fmt.Println(i)
}

// ou bien 

i := 0 
for i < 10 {
    fmt.Println(i)
    i = i + 1
}

Pour exécuter l’exemple : Playground

Instructions de branchement conditionnel

Condition

Une condition permet de faire des instructions si la condition est vraie (if). On peut effectuer des instructions si la condition est fausse (else). Il est possible de faire une succession de tests avec if/else if/.../else.

var a int = 3
if a < 0{
    fmt.Println(a, "negatif")
} else if a > 0 {
    fmt.Println(a, "positif")
} else {
    fmt.Println(a, "nul")
}

Pour exécuter l’exemple : Playground

Switch

switch permet de faire une succession de cas possibles au lieu de plusieurs tests successifs.

a := 1
switch a%2 {
    case 0:Instructions de branchement non conditionnel
        fmt.Println("pair")
    case 1:
        fmt.Println("impair")
}

Pour exécuter l’exemple : Playground

Instructions de branchement non conditionnel

Break

break permet de sortir de la boucle dans laquelle se trouve l’instruction.

for i:=0; i < 10; i++ {
    if i == 5 {
        break
    }
    fmt.Println(i)
}

Pour exécuter l’exemple : Playground

Collections

Tableau

Un tableau permet de déclarer un ensemble fini (à une ou plusieurs dimensions) et ordonné de variables ayant le même type.

var b [2] int
b[0]=0
b[1]=1

// ou directement 

b := [2]int{0, 1}

Pour exécuter l’exemple : Playground

Slice

make permet de déclarer une slice (tableau dynamique) à une ou plusieurs dimensions.

s := make([]string, 2)
s[0] = "a"
s[1] = "b"

// ou directement  

s := []string{"a", "b"}

Pour exécuter l’exemple : Playground

Map

Une map permet de stocker des valeurs en leur associant une clé.

m := make(map[string]int)
m["mehdi"] = 1
m["clement"] = 2

Pour exécuter l’exemple : Playground

Opérations sur les collections

len()

len() permet de récupérer la taille d’un tableau, d’un string ou d’une slice.

var a [2] int
fmt.Println(len(a))

Pour exécuter l’exemple : Playground

append()

append() permet d’ajouter un élément à la slice.

s := make([]string, 2)
s[0] = "a"
s[1] = "b"
s = append(s, "c") 

Pour exécuter l’exemple : Playground

copy()

copy() permet de copier une slice dans une autre.

s := make([]string, 2)
s[0] = "a"
s[1] = "b"
c := make([]string, len(s))
copy(c, s) 

Pour exécuter l’exemple : Playground

delete()

delete() permet de supprimer une valeur dans la map.

m := make(map[string]int)
m["mehdi"] = 1
m["clement"] = 2
delete(m, "clement")

Pour exécuter l’exemple : Playground

identificateur _

Cet identificateur _ permet de déclarer une variable que l’on veut ignorer. Ici, l’appel m["clement"] permet de savoir si une valeur ayant la clé “clement” est présente (true ou false pour la variable test1). Le premier argument permet de récupérer sa position, or, dans notre exemple, il ne nous est pas utile : il est donc ignoré grâce à _.

m := make(map[string]int)
m["mehdi"] = 1
m["clement"] = 2
_, test1 := m["clement"] // test1 vaut true
_, test2 := m["inconnu"] // test2 vaut false

Pour exécuter l’exemple : Playground

range

range permet d’itérer facilement dans une structure de tableau, de slice ou de map.

tab := []int{1, 2, 3}
somme := 0
for _, val := range tab {
    somme += val
}
fmt.Println("Somme:", somme)

Pour exécuter l’exemple : Playground

Structure

Déclarer une structure se fait avec le mot clé struct. Une structure est un nouveau type de variables possédant plusieurs champs.

type etudiant struct {
    nom string
    num  int
}

func main() {
    e := etudiant{nom: "Clement", num: 21501810}
    fmt.Println(e)
}

Pour exécuter l’exemple : Playground

Appels de suites d’opérations

Fonction

Déclarer une fonction se fait avec le mot clé func. Une fonction peut avoir plusieurs retours.

func calcul1 (val1 int, val2 int) int {
    return val1 + val2
}

func calcul2 (val1 int, val2 int) (int, int){
    return val1 + val2, val1 - val2
}

func main() {
    var test1, test2, test3 int = 0, 0, 0
    test1, test2 = calcul2(2,3)
    test3 = calcul1(1,2)
}

Pour exécuter l’exemple : Playground

Méthode

Une méthode correspond à une fonction déclarée pour une structure (hors de la déclaration de la structure). On peut la comparer aux méthodes du langage Java.

func (e etudiant) change_num (nouveau int) etudiant{
    e.num=nouveau
    return e
}

func main() {
    e := etudiant{nom: "Clement", num: 21501810}
    e = e.change_num(21500000)
    fmt.Println(e)
}

Pour exécuter l’exemple : Playground

Interface

Une interface permet de regrouper des signatures de méthodes communes à plusieurs structures.

type politesse interface {
    saluer() string
}

type francais struct {
    nom string
}

func (f francais) saluer() string {
    return "bonjour"
}

type anglais struct {
    name string
}

func (a anglais) saluer() string{
    return "hello"
}

func parler(p politesse) {
    fmt.Println(p.saluer())
}

func main() {
    angl := anglais{name: "James"}
    fran := francais{nom: "Jean"}
    parler(angl) // affiche "hello"
    parler(fran) // affiche "bonjour"
}

Pour exécuter l’exemple : Playground

Ligne de commande et Arguments

Il est possible en langage Go de récupérer les arguments tapés par l’utilisateur lors d’un appel d’un programme. Dans l’exemple ci dessous, on va d’abord compiler avec go build commandes.go. Puis, on va exécuter le programme avec par exemple ./commandes test1 test2 test3. Ici, commandeTotale sera [./commandes test1 test2 test3] et commandesSansAppelProgr sera [test1 test2 test3].

// filename : commandes.go

package main

import "fmt"
import "os"

func main() {
    // os.Args récupére les différents mots constituant la commande
    commandeTotale := os.Args
    // os.Args[1:] récupère tous les mots sauf le premier (appel du programme)
    commandeSansAppelProgr := os.Args[1:]

    fmt.Println(commandeTotale)
    fmt.Println(commandeSansAppelProgr)
}

Pour exécuter l’exemple : Playground

Bibliothèques du langage Go

Principales bibliothèques standards

Bibliothèque fmt

fmt est la bibliothèque permettant de gérer les entrées-sorties de l’utilisateur. En langage C, on peut donc la comparer à la bibliothèque stdio.h. On peut utiliser la fonction Printf pour faire un affichage “formaté” et Scanf pour récupérer l’entrée de l’utilisateur (le clavier par défaut).

package main

import "fmt"

func main() {
    test := 2
    fmt.Printf("test = %d \n", test)
    var entree int
    fmt.Scanf("%d", &entree)
    fmt.Printf("entree : %d\n", entree)
    /* 
        affiche "test = 2"
        puis attend l'entrée de l'utilisateur
        Si l'utilisateur écrit "3" alors l'affichage sera "entrée : 3"
    */
}

Pour exécuter l’exemple : Playground

Bibliothèque errors

Les erreurs errors permettent de gérer les exceptions en langage Go.

package main

import "fmt"
import "errors"

func verifie_positif (nombre float32){
    if(nombre < 0){
        // panic permet de sortir du programme et d'afficher l'exception lancée
        panic(errors.New("Ce nombre ne doit pas etre negatif"))
    }
}

func quotient (num float32, denom float32) (float32, error){
    if denom == 0 {
        return -1, errors.New("Erreur mathematique")
    }else {
        return num / denom, nil
    }
}

func main() {
    var c1 float32
    var err error
    var a1, b1 float32 = 1,2
    c1,err = quotient(a1, b1)
    fmt.Println(c1)
    fmt.Println(err)
    verifie_positif(12.0)
}

Pour exécuter l’exemple : Playground

Bibliothèque os

La bibliothèque os est très utile pour la gestion des processus, des ouvertures et fermetures de fichiers, la manipulation de dossiers et des permissions.

Dans cet exemple, on ouvre en écriture le fichier test_ouverture.txt (crée un nouveau fichier s’il n’existe pas). Puis, on écrit dans le fichier pour enfin le fermer.

package main

import "fmt"
import "os"

func main() {
    f, err1 := os.OpenFile("test_ouverture.txt", os.O_WRONLY|os.O_CREATE, 0644)
    if err1 != nil {
        panic(err1)
    }
    nb_octets, err2 := f.WriteString("voici un test")
    if err2 != nil {
        panic(err2)
    }
    fmt.Println("Nb d'octets écrits dans le fichier : ", nb_octets)
    err3 := f.Close();
    if err3 != nil {
        panic(err3)
    }
}

Pour exécuter l’exemple : Playground

Bibliothèque io

io est la bibliothèque permettant notamment d’interagir avec les fichiers. Il est donc possible de lire et d’écrire dans des fichiers. La différence avec os est le fait que io est plus “haut niveau” que os notamment avec la manipulation des fichiers.

Dans cet exemple, on va lire en entier le fichier test1.txt et recopier son contenu dans le fichier test1_copie.txt. A noter que si le fichier test1_copie.txt n’existe pas, il le crée ; sinon, il l’écrase.

package main

import "io/ioutil"

func main(){

    donnees_copiees, err1 := ioutil.ReadFile("test1.txt")
    if err1 != nil {
        panic(err1)
    }

    donnees_a_recopier := []byte(string(donnees_copiees))
    err2 := ioutil.WriteFile("test1_copie.txt", donnees_a_recopier, 0644) // 0644 correspond aux permissions.
    if err2 != nil {
        panic(err2)
    }

}

Pour exécuter l’exemple : Playground

Bibliothèque strings

strings permet de gérer la manipulation de chaînes de caractères. Elle est comparable à la manipulation de string en langage Java.

package main

import "fmt"
import "strings"

func main() {
    // Count compte le nombre de sous-chaines ("ca") dans un string ("cacao")
    nb1 := strings.Count("cacao", "ca")
    fmt.Println("Il y a", nb1, "\"ca\" dans \"cacao\"")

    // Index renvoie le numéro de la première case de la sous-chaine ("a") dans un string ("cacao")
    nb2 := strings.Index("cacao", "a")
    fmt.Println(nb2)

    // Join concatène un ensemble de string par un séparateur 
    // (si on ne souhaite pas de séparateur il faut mettre "")
    chaine1 := strings.Join([]string{"clement", "mehdi", "TER", "master"}, ", ")
    fmt.Println(chaine1)

    // Repeat concatène un certain nombre de fois (4) un string ("ah")
    chaine2 := strings.Repeat("ah",4)
    fmt.Println(chaine2)

}

Pour exécuter l’exemple : Playground

Bibliothèque time

La bibliothèque time propose des fonctions permettant de mesurer et d’afficher le temps. Celle-ci est comparable à time.h en C et à ctime en C++. La fonction Now() permet de stocker l’instant. Sub permet de calculer avec précision la différence entre deux instants.

package main

import "fmt"
import "time"

func main() {
    t1 := time.Now()
    fmt.Print(t1.Day(), " ", t1.Month(), " ", t1.Year(), " - ")
    fmt.Println(t1.Hour(), ":", t1.Minute(), ":", t1.Second(), ":", t1.Nanosecond())

    t2 := time.Now()
    difference := t2.Sub(t1)
    fmt.Println(difference)
}

Pour exécuter l’exemple : Playground

Principales bibliothèques tierces

Il existe plusieurs bibliothèques tierces, qui sont pour la plupart une extension de certaines bibliothèques standards sur Go, notamment crypto, image, net, sync ou time. Il existe d’autres bibliothèques non standards tels que :

Bibliothèque debug

Cette bibliothèque debug est une librairie expérimentale qui permet au développeur d’applications Go, de gérer plus facilement le débuggage de ses programmes.

Bibliothèque mobile

La bibliothèque mobile permet d’utiliser des programmes Go pour l’intégrer à des applications pour smartphones (tels que Android et iOS).

Outils de développement

Présentation

Le langage Go est un langage très récent (première version en 2009) et est en forte expansion comme langage populaire pour des applications. De nombreux IDE sont disponibles pour programmer en Go, tels que Eclipse (avec GoClipse comme plugin), IntelliJ, Sublime Text … Ils permettent de programmer plus facilement en Go, notamment avec la reconnaissance de syntaxe Go.

Pour plus d’informations sur les IDE supportant Go : IDEsAndTextEditorPlugins

Commandes

Pour obtenir toutes les fonctionnalités afin de programmer en langage Go, il suffit d’installer “golang-go”, notamment en tapant la commande suivante sur Linux : sudo apt-get install golang-go.

Ainsi, on peut effectuer la commande go [commande] [arguments]. Il existe plusieurs commandes importantes :

Pour plus d’informations, notamment sur les commandes ainsi que sur les installations et manipulations à effectuer : CommandesInstallationsGo

Compilation

Lors des manipulations à effectuer, il a fallu, entre autre, choisir un $GOPATH : il correspond au chemin où chercher les différentes dépendances (non standards). Pour pouvoir créer un projet modulaire en langage Go, il va falloir créer un dossier $GOPATH/src/pkg avec pkg le nom du package à créer.

Dans notre exemple, nous allons créer le package point qui contiendra une structure point et une fonction d’affichage, puis, le package projet qui contiendra le main et qui appellera un point.

/* $GOPATH/src/projet/projet.go */

package main

import "fmt"
import "point"

func main() {
    p := point.Point{X : 3, Y: 2}
    fmt.Println(point.PrintPoint(p))
}
/* $GOPATH/src/point/point.go */

package point

import "strconv"

type Point struct {
    X int
    Y int
}

func PrintPoint (p Point) string {
    return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
}

func PrintPointReverse (p Point) string {
    return "(" + strconv.Itoa(p.Y) + "," + strconv.Itoa(p.X) + ")"
}

Il est important de noter que :

Il est maintenant nécessaire de compiler et exécuter cet exemple : pour cela, il faut aller dans l’arborescence $GOPATH/ Pour compiler la librairie point, on lance la commande suivante go build point/. Enfin, pour compiler le programme principal, on utilise go install projet/. Ainsi, un exécutable projet apparaîtra dans le dossier $GOPATH/bin/, qu’on exécutera avec ./bin/projet.

Pour télécharger l’exemple : ZIP

Tests unitaires

Il est possible en langage Go de réaliser des tests unitaires afin d’augmenter la confiance de programmeur pour des portions de code. On peut donc tester des fonctions. Cela est notamment comparable à Junit en langage Java ou à CUnit en langage C.

Pour tester les fonctions du fichier XXX.go du package YYY, il suffit de créer un fichier test_XXX.go dans le package YYY. Dans le précédent exemple, on a donc créer test_point.go. Pour pouvoir exécuter les tests unitaires associés au module point, il suffit de faire la commande go test point.

/* $GOPATH/src/point/test_point.go */

package point

import "testing"

func TestPrintPoint(t *testing.T) {
    p := Point{X : 3, Y: 2}
    chaineCalcul := PrintPoint(p)
    chaineResultat := "(3,2)"
    if chaineCalcul != chaineResultat {
       t.Errorf("PrintPoint() incorrect : calcule: \"%s\", et veut: \"%s\".", chaineCalcul, chaineResultat)
    }
}

func TestPrintPointReverse(t *testing.T) {
    p := Point{X : 3, Y: 2}
    chaineCalcul := PrintPointReverse(p)
    chaineResultat := "(2,3)"
    if chaineCalcul != chaineResultat {
       t.Errorf("PrintPoint() incorrect : calcule: \"%s\", et veut: \"%s\".", chaineCalcul, chaineResultat)
    }
}

Il est important de noter ici que :

Pour télécharger l’exemple : ZIP

Documentation

La documentation d’un programme Go est possible, notamment avec l’outil Godoc. Ainsi, il permet de générer une documentation précise (comparable à Javadoc en Java ou Doxygen en C). Pour cela, on laisse des commentaires de la forme // Commentaire. au dessus de chaque structure, package et fonction. Lorsque les commentaires sont bien effectués, on génère la documentation avec la commande suivante : godoc -http=:8080 et on y accède par un navigateur avec localhost:8080/pkg/[package] avec [package]le nom du package dont l’on veut voir la documentation.

// Package point concernant tout ce qui concerne l'entité Point. 
package point

import "strconv"

// Point est une structure ayant une abscisse et une ordonnée. 
type Point struct {
    // X abscisse du point
    X int

    // Y ordonnee du point
    Y int
}

// PrintPoint affiche l'abscisse suivie de l'ordonnée. 
func PrintPoint (p Point) string {
    return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
}

// PrintPointReverse affiche l'ordonnée suivie de l'abscisse. 
func PrintPointReverse (p Point) string {
    return "(" + strconv.Itoa(p.Y) + "," + strconv.Itoa(p.X) + ")"
}

Ici, il est utile de visualiser la documentation du package point. Pour cela, on va sur localhost:8080/pkg/point et on obtient :

Documentation point.go

Ressources d’apprentissage