Utiliser les imports de package go
Dans cet article nous examinerons plusieurs variantes du mot-clé
import. Une déclaration d'import signale au compilateur qu'un fichier source contenant l'import d'un paquet go dépend de ce paquet. Ce qui permet à ce fichier source d'utiliser des identificateurs (variables, fonctions) contenus dans ce paquet.
Bien entendu, un paquet ne peut pas s'inclure lui-même.
Importer un paquet sans utiliser les fonctionnalités qu'il contient provoque une erreur de compilation. C'est un peu pénible, mais cela permet de garder un code propre et concis ne contenant que ce qui est nécessaire à l'exécution du code. L'effet bénéfique de cette règle stricte est de limiter la taille du binaire issue de la compilation au strict nécessaire.
Comment importer et utiliser différents paquets go ayant le même nom ?
Si on essaye d'utiliser deux packages go ayant le même nom, comme
math/rand et
crypto/rand ou
text/template et
html/template, on obtient l'erreur suivante :
rand redeclared as imported package name ainsi que des erreurs
undefined:.
Pour inclure deux packages ayant le même nom, il faut renommer l'un d'entre eux au moment de l'import. Comme dans cet exemple de code où le package
crypto/rand a été renommé en
randcrypt de manière à ne pas être considéré comme déjà utilisé au moment de la compilation.
package main
import (
"fmt"
"math/rand"
randcrypt "crypto/rand"
)
func main() {
fmt.Println("Au hasard : ", rand.Intn(100))
b := make([]byte, 10)
randcrypt.Read(b)
fmt.Printf("Au hasard : %v\n", string(b))
}
Fusionner un paquet dans le package qui l'importe
Lorsque, par exemple, on utilise la fonction
Println du paquet
fmt, il faut utiliser le nom du paquet
fmt en tant que préfixe (on parle aussi d'identificateur qualifié ou
qualified identifier). Ainsi, comme dans l'exemple de code précédent, on écrira
fmt.Println("Au hasard : ", rand.Intn(100)) pour afficher à l'écran un nombre choisit au hasard entre 0 et 100.
golang permet, au moment de l'import, de préciser que l'on souhaite se passer des préfixes lors que l'on appelle une fonction d'un paquet. Un peu comme si le code du package étant fusionné dans le paquet où il est importé. Dans l'exemple ci-dessous, le paquet
fmt est comme
fusionné avec le paquet
main:
package main
import (
. "fmt"
)
func main() {
Println("Appel de la fonction Println sans utliser le prefixe fmt")
}
Jouer sur les effets de bord
Décrire l'effet de bord est l'occasion de parler du mystérieux paquet
expvar. Comme nous l'avons vu précédemment, le fait ne pas faire appel à des identificateurs contenus dans un paquet importé provoque une erreur de compilation. Ce qui est embêtant, car certains packages contiennent du code utilitaire apportant des fonctionnalités supplémentaires à un programme golang sans qu'il soit nécessaire de faire appel à ce code. Un peu à la manière d'un plug-in.
C'est le cas du package
expvar qui contient un
handler HTTP donnant des informations sur l'état d'une application web écrite en go. Voici un exemple d'utilisation :
package main
import (
"net/http"
_ "expvar"
)
func main() {
http.ListenAndServe(":9999", nil)
}
Si on écrivait la ligne
import "expvar", on obtiendrait une erreur de type
imported and not used: "expvar". Mais l'indentificateur blanc (
blank identifier) permet d'importer un paquet seulement pour ses effets de bord et pas forcément pour utiliser une de ses fonctions.
Vous pouvez exécuter le code ci-dessus, puis accéder à l'URL
http://localhost:9999/debug/vars qui donne des informations sur les variables publiques de votre webapp. Lorsque la documentation parle de
variable publique, il s'agit d'indicateurs sur le programme (comme les indicateurs sur la consommation mémoire, la pile ou le tas), mais pas sur les variables déclarées en dehors des fonctions.
Récapitulatif
Si vous avez bien suivi mon article jusqu'à maintenant, vous comprendrez que l'on peut donc écrire le code suivant sans erreur :
package main
import (
. "fmt"
"math/rand"
"net/http"
randcrypt "crypto/rand"
_ "expvar"
)
func main() {
Println("Au hasard : ", rand.Intn(100))
b := make([]byte, 10)
randcrypt.Read(b)
Println("Au hasard : %v", string(b))
http.ListenAndServe(":9999", nil)
}
Si on examine le code de la fonction principale :
- Println au lieu de fmt.Println ne pose pas de problème grâce à l'import-fusion . "fmt"
- On peut faire appel à deux paquets portant le même nom rand parce que l'un d'entre eux est renommé en randcrypt
- Nous bénéficions des handlers HTTP du paquet expvar grâce à l'effet de bord de l'import _ "expvar"