← Go EspañolChapter 09 of 13

Interfaces

## Objetivos de Aprendizaje - Comprender interfaces como contratos - Implementar interfaces implícitamente - Usar interface vacía - Dominar aserciones y switches de tipo - Diseñar con interfaces ## ¿Qué es una Interface? Una interface define un contrato. Los tipos que implementan una interface deben proporcionar todos los métodos especificados. ## Declaración ### Interface Básica ```go type Speaker interface { Speak() string } ``` ### Múltiples Métodos ```go type Animal interface { Speak() string Move() string } ``` ## Implementación ### Implementación Implícita Los tipos implementan interfaces implícitamente - sin declaración explícita. ```go type Dog struct { Name string } func (d Dog) Speak() string { return "¡Guau!" } func main() { var s Speaker = Dog{Name: "Buddy"} fmt.Println(s.Speak()) // ¡Guau! } ``` ### Ambas Implementaciones ```go type Cat struct{} func (c Cat) Speak() string { return "¡Miau!" } type Cow struct{} func (c Cow) Speak() string { return "¡Muuu!" } func main() { animals := []Speaker{Cat{}, Cow{}} for _, animal := range animals { fmt.Println(animal.Speak()) } } ``` ## Interface Vacía ### interface{} (interface vacía) ```go var i interface{} = "hello" i = 42 i = true ``` ### Acepta Cualquier Cosa ```go func printAll(items ...interface{}) { for _, item := range items { fmt.Println(item) } } printAll(1, "hello", true, 3.14) ``` ## Aserciones de Tipo ### Aserción Básica ```go var i interface{} = "hello" s := i.(string) // Panics si no es string fmt.Println(s) // hello s, ok := i.(string) // Seguro: ok es false si no es string fmt.Println(s, ok) // hello true ``` ### Asertar Tipo Incorrecto ```go var i interface{} = 42 s, ok := i.(string) fmt.Println(s, ok) // "" false (sin panic) ``` ### Panic en Fallo ```go var i interface{} = 42 s := i.(string) // PANIC: conversión de interface fallida ``` ## Type Switch ### switch en Tipo ```go func describe(i interface{}) { switch v := i.(type) { case int: fmt.Printf("Entero: %d\n", v) case string: fmt.Printf("Cadena: %s (longitud %d)\n", v, len(v)) case bool: fmt.Printf("Booleano: %t\n", v) case float64: fmt.Printf("Float64: %.2f\n", v) default: fmt.Printf("Tipo desconocido: %T\n", v) } } func main() { describe(42) describe("hello") describe(true) } ``` ### Type Switch con Interface ```go type Shape interface { Area() float64 } type Circle struct{ Radius float64 } type Rectangle struct{ Width, Height float64 } func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius } func (r Rectangle) Area() float64 { return r.Width * r.Height } func printArea(s Shape) { switch shape := s.(type) { case Circle: fmt.Printf("Círculo con radio %.2f, área %.2f\n", shape.Radius, shape.Area()) case Rectangle: fmt.Printf("Rectángulo %.2f x %.2f, área %.2f\n", shape.Width, shape.Height, shape.Area()) default: fmt.Println("Forma desconocida") } } ``` ## Valores de Interface ### Estructura Un valor de interface tiene dos componentes: 1. Tipo dinámico 2. Valor dinámico ```go var s Speaker fmt.Printf("%+v\n", s) // s = Dog{Name: "Buddy"} fmt.Printf("%+v\n", s) // {Name:Buddy} ``` ### Interface Nil ```go var s Speaker = nil if s == nil { fmt.Println("La interface es nil") } ``` ### Interface con Valor Nil ```go var s Speaker = (*Dog)(nil) if s == nil { fmt.Println("La interface es nil") } else { fmt.Println("La interface no es nil, pero el valor es nil") } ``` ## Errors ### Interface error ```go type error interface { Error() string } ``` ### Error Personalizado ```go type DivisionError struct { Dividend, Divisor float64 } func (e *DivisionError) Error() string { return fmt.Sprintf("no se puede dividir %.2f por cero", e.Dividend) } func divide(a, b float64) (float64, error) { if b == 0 { return 0, &DivisionError{Dividend: a, Divisor: b} } return a / b, nil } ``` ### Usando Errors ```go result, err := divide(10, 0) if err != nil { fmt.Println("Error:", err) return } fmt.Println("Resultado:", result) ``` ## io.Reader e io.Writer ### io.Reader ```go type Reader interface { Read(p []byte) (n int, err error) } ``` ### io.Writer ```go type Writer interface { Write(p []byte) (n int, err error) } ``` ### Usando Readers ```go import "io" import "strings" reader := strings.NewReader("Hello, World!") buf := make([]byte, 5) for { n, err := reader.Read(buf) if err == io.EOF { break } fmt.Printf("Leídos %d bytes: %s\n", n, buf[:n]) } ``` ### Usando Writers ```go import "os" file, err := os.Create("output.txt") if err != nil { log.Fatal(err) } defer file.Close() n, err := file.Write([]byte("Hello, World!")) fmt.Printf("Escribidos %d bytes\n", n) ``` ## Stringer ### fmt.Stringer ```go type Stringer interface { String() string } ``` ### Implementación de Stringer ```go type Person struct { Name string Age int } func (p Person) String() string { return fmt.Sprintf("%s (%d)", p.Name, p.Age) } func main() { p := Person{Name: "Alice", Age: 30} fmt.Println(p) // Alice (30) } ``` ## Composición de Interfaces ### Incrustar Interfaces ```go type Reader interface { Read(p []byte) (n int, err error) } type Closer interface { Close() error } type ReadCloser interface { Reader Closer } ``` ## Mejores Prácticas ### Aceptar Interfaces, Retornar Structs ```go func NewService(repo Repository) Service { return &service{repo: repo} } type Service interface { DoSomething() error } ``` ### Mantener Interfaces Pequeñas ```go // Interface pequeña (preferido) type Writer interface { Write([]byte) (int, error) } // Interface grande (evitar) type Everything interface { Read([]byte) (int, error) Write([]byte) (int, error) Close() error // ... } ``` ## Verificación de Interface Nil ```go func doSomething(i interface{}) { if i == nil { fmt.Println("interface nil") return } fmt.Printf("Valor: %v, Tipo: %T\n", i, i) } ``` ## Resumen - Las interfaces definen contratos (conjuntos de métodos) - Los tipos implementan interfaces implícitamente - La interface vacía `interface{}` acepta cualquier tipo - Aserciones de tipo: `i.(T)` con idiom comma-ok - Type switch: `switch v := i.(type)` - Interface error: `Error() string` - io.Reader e io.Writer son interfaces comunes - Aceptar interfaces, retornar tipos concretos - Mantener interfaces pequeñas y enfocadas

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →