Methods interfaces
Méthodes et interfaces en Go¶
Go n'est pas orienté objet (pas de notion de class ou d'hérirage). Par contre, on peut définir des méthodes sur des types existants. Les méthodes sur des pointeurs permettent de modifier l'état de l'objet.
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v *Vertex) swap() {
v.X, v.Y = v.Y, v.X
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
v.swap()
fmt.Println(v)
}
5
{4 3}
On peut définir des méthodes sur uniquement sur des types locaux (définis dans le même package).
package main
import (
"fmt"
"math"
)
type MyInt int
func (i MyInt) reverseSign() int {
return int(-i)
}
func main() {
i := MyInt(10)
fmt.Println(i.reverseSign())
}
-10
Interfaces¶
Est un ensemble de signatures de méthodes. La convention en Go est de finir le nom d'une interface par "er" (ex: Reader, Writer, etc.). L'implémentation d'une interface est implicite: un type implémente une interface s'il définit toutes les méthodes de cette interface (assimilable au duck typing).
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
a = f // a MyFloat implements Abser
a = &v // a *Vertex implements Abser
// In the following line, v is a Vertex (not *Vertex)
// and does NOT implement Abser.
//a = v
fmt.Println(a.Abs())
}
5
Gestion de la nullabilité¶
Une interface a une valeur nil par défaut. Appeler une méthode sur un nil engendre une erreur à l'exécution (au runtime).
package main
import "fmt"
type I interface {
M()
}
func main() {
var i I
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
(<nil>, <nil>)
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x10463ea38]
goroutine 1 [running]:
main.main()
[[ Cell [4] Line 12 ]] /var/folders/sj/67508vy94d1346kyt0w_kcjw0000gn/T/gonb_d8a79db2/main.go:30 +0x28
exit status 2
Il est possible de gérer les valeur null de l'interface dans l'implémentation de ses méthodes. Ces méthodes doivent dans ce cas iplémenter une méthode sur un pointeur de l'interface.
package main
import "fmt"
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
func main() {
var i I
var t *T
i = t
describe(i)
i.M()
i = &T{"hello"}
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
(<nil>, *main.T)
<nil>
(&{hello}, *main.T)
hello