Lezioni del modulo (2/5)
Type assertion
Una type assertion estrae il tipo concreto da un valore di interfaccia.
Serve quando hai in mano un interface{} (o un'interfaccia "alta") e ti
serve trattarlo come il suo tipo specifico per accedere a campi o metodi
non presenti nell'interfaccia.
Sintassi
var i interface{} = "ciao"
s := i.(string) // forma "panic": panic se non è string
s, ok := i.(string) // forma "comma ok": ok = false se non è stringDue forme, due semantiche:
| Forma | Successo | Fallimento |
|---|---|---|
v := i.(T) | v = valore di tipo T | panic a runtime |
v, ok := i.(T) | v=..., ok=true | v = zero value di T, ok=false |
Forma "comma ok": la più sicura
var i interface{} = 42
if s, ok := i.(string); ok {
fmt.Println("è stringa:", s)
} else {
fmt.Println("non è stringa, ignoro")
}ok ti permette di gestire il caso "tipo sbagliato" senza panic. È il
pattern idiomatico nella stragrande maggioranza dei casi.
Assertion verso un'interfaccia
L'asserzione non funziona solo verso tipi concreti, ma anche verso altre interfacce:
type Closer interface { Close() error }
func tryClose(x interface{}) {
if c, ok := x.(Closer); ok {
c.Close()
}
}Pattern molto comune nella standard library: "se il mio input è anche
un io.Closer, chiamo Close al termine".
Assertion su puntatori vs valori
L'asserzione deve corrispondere ESATTAMENTE al tipo dinamico:
type Cat struct{}
func (c *Cat) Meow() {}
var a interface{} = &Cat{}
c1, ok := a.(*Cat) // ok = true
c2, ok := a.(Cat) // ok = false: dentro c'è *Cat, non Cat*Cat e Cat sono tipi distinti per il type system.
Quando usare assertion vs type switch
- 1 solo tipo possibile, controllo "feature-detect" (es. cast a un'interfaccia opzionale): type assertion con
comma ok. - 2+ tipi possibili, dispatch su più rami: type switch (prossima lezione).
Prova tu
Usa il pattern comma ok per estrarre una string da i.
Mostra suggerimento
Sintassi: `v, ok := i.(T)`.
Soluzione disponibile dopo 3 tentativi
Type assertion verso int senza comma ok (assumi che i contenga un int).
Mostra suggerimento
Senza `ok` si suppone che il tipo sia certo; altrimenti panic.
Soluzione disponibile dopo 3 tentativi
Cosa succede con `s := i.(string)` se i contiene un int?
var i interface{} = 42
s := i.(string)Recap
v := i.(T): panic se il tipo dinamico ≠ T.v, ok := i.(T): pattern sicuro, controllaok.- Vale anche verso un'altra interfaccia ("feature detect").
Te*Tsono tipi distinti per l'assertion.- 1 tipo → assertion; 2+ tipi → type switch.