Aller au contenu

Programmation en Go/Interfaces

Un livre de Wikilivres.

Définition d'une interface

[modifier | modifier le wikicode]

Une interface est un ensemble de méthodes, c'est-à-dire des fonctions qu'il est possible d'implémenter pour un type défini. En voici un exemple, une interface de tri:

 type sort.Interface interface {
   Len() int
   Less(i, j int) bool
   Swap(i, j int)
 }

Cette interface permet de trier n'importe quelle structure de données consécutives. Il suffit de définir les méthode Len(), Less() et Swap() et nous pourrons appeler sort() sur cette structure de données.

Nous pouvons par exemple définir cette interface pour un tableau d'entiers:

 type Sequence []int
 
 func (s Sequence) Len() int {
    // longueur de s
    return len(s)
 }
 func (s Sequence) Less(i, j int) bool {
    // retourne vrai si l'élément d'indice i est inférieur à l'élément d'indice j
    return s[i] < s[j]
 }
 func (s Sequence) Swap(i, j int) {
    // échange deux éléments
    s[i], s[j] = s[j], s[i]
 }

Ainsi la syntaxe fait précéder le nom de la méthode du type défini entre parenthèses. Nous pouvons maintenant trier une séquence en faisant:

 var seq Sequence
 sort.Sort(seq)

Note sur les pointeurs

[modifier | modifier le wikicode]

Lorsque l'on implémente une méthode sur une structure, il est d'usage de déclarer la méthode sur un type pointeur de cette structure, pour éviter le passage par valeur:

 type Foo struct {...}
 func (foo *Foo) String() string {return ...}

Héritage d'interfaces

[modifier | modifier le wikicode]

En incluant un nom de type précédé d'une étoile dans une structure, sans le nommer, la structure hérite de toutes les interfaces de cette structure en les lui déléguant.

 type Tache struct {
    Commande string
    *log.Logger
 }

Ensuite on appelle

 tache.Log()

qui est délégué au membre log.Logger de la structure.

Héritage multiple

[modifier | modifier le wikicode]

Il est possible d'hériter de manière multiple comme dans l'exemple suivant:

 type ReaderWriter struct {
   *io.Reader
   *io.Writer
 }

Il est alors d'usage de définir un constructeur, si nécessaire, pour la structure Tache, que l'on nommera "NewTache":

 func NewTache(commande string, journaliseur *log.Logger) *Tache {
    return &Tache{commande, journaliseur}
 }