A la découverte du Go



Arnaud "Arhuman" Assad (arhuman@gmail.com)
Aussi sur Twitter - Linkedin - Github

Le langage Go

  • Créé en 2009 par Google
    (Robert Griesemer, Rob Pike et Ken Thompson)
  • Inspiré du C et de Pascal
  • Langage compilé
  • Récupérateur de mémoire (garbage-collected)

OSCON 2010

Go aims to combine the safety and performance of a statically typed compiled language with the expressiveness and convenience of a dynamically typed interpreted language.

It also aims to be suitable for modern systems - large scale - programming.

-- Rob Pike

Go(lang) exemple


package main

import "fmt"

func main() {
    list := []int{31, 41, 59, 26, 53, 58, 97, 93, 23, 84}
    fmt.Println("unsorted:", list)

    bubblesort(list)
    fmt.Println("sorted!  ", list)
}

func bubblesort(a []int) {
    for itemCount := len(a) - 1; ; itemCount-- {
        hasChanged := false
        for index := 0; index < itemCount; index++ {
                                   if a[index] > a[index+1] {
                a[index], a[index+1] = a[index+1], a[index]
                hasChanged = true
            }
        }
        if hasChanged == false {
            break
        }
    }
}
                        

Le langage Go!

  • Créé en 2003 par Keith Clark et Francis McCabe.
  • Programmation concurrentielle

Go! - exemple


Gender::= male | female.

person <˜ {dayOfBirth:[]=>day. age:[]=>integer.
           gender:[]=>Gender. name:[]=>string.
           home:[]=>string. lives:[string]{}}.

person:[string,day,Gender,string]$=person.

person(Nm,Born,Sx,Hm)..{
  dayOfBirth()=>Born.
  age() => yearsBetween(now(),Born).
  gender()=>Sx.
  name()=>Nm.
  home()=>Hm.
  lives(Pl) :- Pl=home().
  yearsBetween:[integer,day]=>integer.
  yearsBetween(...) => ..
}.

newPerson:[string,day,Gender,string]=>person.

newPerson(Nm,Born,Sx,Hm)=>$person(Nm,Born,Sx,Hm).
                        

Mais aussi

Et aussi

  • Go Go Power Rangers!!!
  • Python is the way to go
  • Go sport / Go voyages
  • Pokemon Go

Et donc Golang...

  • Uniquement pour le SEO
  • Assez répandu
  • Pas recommandé par Rob Pike

Pourquoi Go ?

  • La simplicité
  • Les interfaces
  • Les goroutines / channels
  • La toolchain
  • La librairie standard
  • Rapidité de compilation

Go un langage simple


    package main

    import "fmt"

    func main() {
        // L'Unicode ça doit être simple...
        fmt.Println("Hello 世界")
    }
                        
fmt Documentation

Une seule boucle


sum := 0
for i := 0; i < 10; i++ {
    sum += i
}

for ; sum > 0; {
    sum -= 1
}

for sum < 1000 {
    sum += 1
}
                        

Types de base

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // alias pour uint8

rune // alias pour int32
     // représente un "code point" Unicode

float32 float64

complex64 complex128

                        

Des types composés


package main

import "fmt"

type Sommet struct {
    X int
    Y int
}

func main() {
    v := Sommet{1, 2}
    v.X = 4
    fmt.Println(v.X)
}
                        

Des slices (et des tableaux)


// Array : taille fixe
var a [10]int


// Slice : taille variable
var b[]int
                        

Des slices


// Des slices de slices
game := [][]string{
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
}

// Morceau de slice retourne un slice
game[1:3] // ou game[1:]

// Ajout
game = append(game, []string{" ", " "," "});

// Boucle for avec range
for i, v := range game {
    fmt.Printf("index=%d valeur=%v\n", i, v)
}
                        

Des maps


type Sommet struct {
    Lat, Long float64
}

var m map[string]Sommet

func main() {
    m = make(map[string]Sommet)
    m["Bell Labs"] = Sommet{
        40.68433, -74.39967,
    }
    fmt.Println(m["Bell Labs"])
}

                        

Des maps


// Affectation
m[key] = elem

// Récupération
elem = m[key]

// Suppression
delete(m, key)

// Test existence
elem, ok = m[key]   //  _, ok = m[key]
                        

First class functions


func compute(fn func(float64, float64) float64) float64 {
    return fn(3, 4)
}

func main() {
    hypot := func(x, y float64) float64 {
        return math.Sqrt(x*x + y*y)
    }
    fmt.Println(hypot(5, 12))

    fmt.Println(compute(hypot))
    fmt.Println(compute(math.Pow))
}
                        

Programation Orientée Objet

  • Héritage
  • Encapsultation
  • Polymorphisme

POO en Go ?

  • Go pas d'héritage (interface)
  • Pas de classe (struct)
  • Polymorphisme

Interfaces

  • Pour principe de substitution de Liskov
    (pas d'héritage)
  • Implicites
    (pas besoin de modifier les packages externes)
  • Peuvent être déroutantes

Struct + fonction => Méthode


type Sommet struct {
    X, Y float64
}

func (s Sommet) Abs() float64 {
    return math.Sqrt(s.X*s.X + s.Y*s.Y)
}
                        

Interface = liste de méthodes


package main

import (
        "fmt"
        "math"
)

type cercle struct {
        rayon float64
}

func (c cercle) aire() float64 {
        return math.Pi * c.rayon * c.rayon
}
func (c cercle) perimetre() float64 {
        return 2 * math.Pi * c.rayon
}

type rectangle struct {
        largeur, hauteur float64
}

func (r rectangle) aire() float64 {
        return r.largeur * r.hauteur
}
func (r rectangle) perimetre() float64 {
        return 2*r.largeur + 2*r.hauteur
}

type surface interface {
        aire() float64
        perimetre() float64
}

func affiche(s surface) {
    fmt.Println(s)
    fmt.Println(s.aire())
    fmt.Println(s.perimetre())
}

func main() {
    c := cercle{rayon: 3}
    r := rectangle{largeur: 1, hauteur: 2}

    affiche(r)
    affiche(c)
}

                        

Goroutines

Goroutines

  • Des millions de goroutines possible
  • 50 fois plus rapide à lancer qu'un thread
  • 2-4K vs 2M sur la stack
  • Changement de contexte peu couteux
  • Un thread système gère plusieurs goroutines

Goroutine - Exemple


package main

import (
    "fmt"
    "time"
)

func longTraitement(d int, s string) {
    time.Sleep(time.Duration(d) * time.Second)
    fmt.Println(s)

}

func main() {
    go longTraitement(3, "Premier long Traitement")
    go longTraitement(2, "Deuxième long Traitement")
    go longTraitement(1, "Troisième long Traitement")
    fmt.Println("Dans main()")

    // Laissons le temps aux goroutines de se terminer
    time.Sleep(time.Duration(4) * time.Second)
}

// Affiche :
// Dans main()
// Troisième long Traitement
// Deuxième long Traitement
// Premier long Traitement
                        

Channels

"Don't communicate by sharing memory, share memory by communicating."
-- Rob Pike

Channels

  • Vont de paire avec les goroutines
  • First class elements
  • Bufferisés ou pas
  • Pas de callback !

Channels


package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
s := []int{7, 2, 8, -9, 4, 0}

c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // receive from c

fmt.Println(x, y, x+y)
}
                        

Toolchain

  • Point d'entrée unique
  • GOPATH
    • go get
    • go build
    • go run
    • go ...
    • go test

Toolchain

  • Intégrable à l'éditeur
    • go import
    • go format
  • Cross compilation
  • Temps de compilation

Temps de compilation

  • Analyse plus simple
    • Pas de dépendances inutilisées
    • Pas de dépendances cycliques
    • Syntaxe régulière
  • Un import => un fichier à charger
  • Format objet avec les exports en début de fichier

Librairie standard bien fournie

HTTP server


package main

import (
    "net/http"
)

func main() {

    fs := http.FileServer(http.Dir("static/"))

    http.Handle("/", fs)
 // http.Handle("/static/", http.StripPrefix("/static/", fs))

    http.ListenAndServe(":8080", nil)
}
                        
net/http Documentation

La killer App ?

Tout un écosytème

Communauté

Un langage en constante amélioration

  • Release fréquentes
    • Modules
    • Webassembly
  • Go 2
    • Generics avec contrat
    • Gestion des erreurs moins fastidieuse

Une chouette mascotte

Go pourquoi faire ?

  • Backend/Système
  • Application avec GUI
  • Browser
  • Embarqué
  • Presque tout sauf du bas niveau

Application avec GUI

Même des jeux 3D

Browser

  • Webassembly
    GOOS=js GOARCH=wasm go build -o main.wasm
  • Gopher.js

Embarqué

Credits




Vous êtes libre de modifier/copier/redistribuer librement cette présentation.

Merci


Des questions ?



N'hésitez pas à prendre contact via Linkedin

Most wanted language *

Position Langage %
1 JavaScript 17.8%
2 Go 15.0%
3 TypeScript 14.6%
4 Kotlin 11.1%
5 Rust 9.5%
6 C++ 9.1%
7 WebAssembly 8.9%
9 Java 8.3%
9 SQL 7.6%
10 C# 7.0%
11 HTML/CSS 6.6%
12 Swift 5.8%
13 C 5.0%


* StackOverflow survey 2019

Tout n'est pas parfait

  • La gestion des erreurs
  • Les générics
  • Manque de packages dans certains domaines
    (Machine Learning...)