Go est un langage de programmation généraliste, sous licence BSD, à typage statique, disposant d'un ramasse-miettes et de facilités pour gérer la concurrence. Ses avantages sont d'être concis et expressif, de compiler très rapidement et de proposer les performances d'un langage compilé avec la souplesse d'un langage interprété.
Après deux ans et demi de développement, la première version stable du langage Go, nommée Go 1, est sortie. Elle vise à apporter de la stabilité sur les prochaines années pour les utilisateurs du langage, mais aussi pour les auteurs, qui vont ainsi pouvoir écrire des livres dont les exemples et explications continueront d'être valables bien après leur sortie. En particulier, cela implique une compatibilité garantie de tout programme écrit avec la version 1.0 vers toutes les versions 1.x.
Notons que le langage a fortement évolué depuis les premières annonces et que son positionnement a également été revu. Par exemple, Go était initialement vendu comme un langage de programmation système mais il est maintenant décrit comme un langage généraliste, ce qui correspond mieux à l'utilisation qui peut en être faite. Autre changement, Go était au départ un projet de Google mais il n'y a plus, aujourd'hui, de mention de Google sur la page d'accueil du site officiel. Cela ne veut pas dire que Google se désintéresse de Go (pour preuve, il est utilisé pour des composants critiques comme vitess pour Youtube) mais que les auteurs du langage souhaitent mettre en avant la communauté qui s'est construite autour du langage.
Des binaires pour Go 1 sont fournis sur le site officiel pour Linux, FreeBSD, Mac OS X et Windows au cas où votre distribution ne fournirait pas encore de paquets officiels.
NdM : merci à Xavier Claude pour la rédaction d'une dépêche sur le même sujet qui a été intégrée à celle-ci.
Hello World
Vous n'échapperez pas au traditionnel Hello world du langage :
package main
import "fmt"
func main() {
fmt.Println("Hello world")
}
Outil go
Un outil, go
, vient avec le langage et permet de faire de nombreuses actions :
- compiler du code source :
go build hello.go
- compiler le code et exécuter la version ainsi compilée :
go run hello.go
- générer la documentation d'un module avec
go doc
- lancer les tests avec
go test
- installer un module :
go get github.com/bmizerany/pat
- reformater le code source d'un programme avec
go fmt
(c'est une manière particulièrement astucieuse d'éviter les discussions sans fin sur le style à adopter sur un programme : il suffit de lancer go fmt sur son code pour qu'il soit formaté selon les bonnes pratiques)
- etc.
UTF-8
Deux des personnes à l'origine du projet ne sont autres que Rob Pike et Ken Thompson, les inventeurs de l'encodage UTF-8. Il est donc naturel que l'encodage par défaut en Go soit l'UTF-8. Cela s'applique notamment pour le nom des variables, même si, dans la pratique, les développeurs se limitent très largement aux caractères ASCII.
Goroutines et canaux
Go offre un mécanisme pour mettre en œuvre de la concurrence appelé goroutine : ce sont des contextes légers d'exécution. Une goroutine est créée en plaçant le mot-clé go
devant l'appel d'une fonction et le langage va ensuite multiplexer les goroutines sur des threads. Cela permet ainsi à un programme Go d'utiliser tous les cœurs d'un CPU.
Un des motto de Go est « Share memory by communicating, don't communicate by sharing memory », que l'on peut traduire par « Partager la mémoire en communiquant, ne pas communiquer en partageant la mémoire ». En pratique, cela veut dire qu'il vaut mieux éviter d'avoir un espace mémoire commun à plusieurs goroutines qui serait protégé par un mutex (même si le langage le permet), mais de privilégier une communication explicite entre les goroutines. Go met à notre disposition pour cela les canaux.
Voici par exemple une go bomb, qui marche de manière similaire à une fork bomb, créant des goroutines jusqu'à saturation des ressources du système :
package main
import "fmt"
func main() {
c := make(chan bool)
go func() {
count := 0
for <- c {
count++
fmt.Println(count)
}
}()
bomb(c)
}
func bomb(tick chan bool) {
for {
tick <- true
go bomb(tick)
}
}
Pour compter le nombre de goroutines lancées, ce programme utilise un canal qui permet à une goroutine particulière d'incrémenter le compteur. Si on lance ce programme, on pourra constater qu'il permet de créer plusieurs centaines de milliers de goroutines avant d'être tué par le noyau quand toute la mémoire aura été consommée.
Polémique sur la gestion de la mémoire
Le ramasse-miette utilisé par l'implémentation actuelle de Go est conservatif (par opposition à précis, conservative vs precise en anglais). Cela veut dire qu'il peut « oublier » de libérer certaines zones mémoires. Certaines personnes ont rencontré des problèmes en 32 bits où des entiers peuvent être mal interprétés par le ramasse-miettes comme des pointeurs pouvant conduire à des fuites de mémoire. Dans la mesure du possible, il est recommandé d'utiliser du 64 bits pour éviter ces problèmes (le risque de confusion est extrêmement plus faible). Les développeurs de Go vont travailler sur ce problème mais le ramasse-miettes est un sujet qui demande du temps et il faut donc s'attendre à une évolution progressive sur le long-terme pour ce point.