Menu
Coddy logo textTech

Duck Typing en Go

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 42 de 107.

El término duck typing proviene del dicho: «Si camina como un pato y grazna como un pato, después es un pato». En Go, esto significa que un tipo no necesita declarar explícitamente que implementa una interfaz. Solo necesita tener los métodos adecuados.

Considera esta interfaz y dos tipos completamente no relacionados:

type Quacker interface {
    Quack() string
}

type Duck struct{}
func (d Duck) Quack() string { return "Quack!" }

type Robot struct{}
func (r Robot) Quack() string { return "Beep-quack!" }

Ni Duck ni Robot mencionan Quacker en ninguna parte de sus definiciones. Sin embargo, ambos satisfacen la interfaz simplemente porque tienen un método Quack() con la firma correcta:

func MakeItQuack(q Quacker) {
    fmt.Println(q.Quack())
}

func main() {
    MakeItQuack(Duck{})   // Quack!
    MakeItQuack(Robot{})  // Beep-quack!
}

Esta satisfacción implícita es poderosa porque te permite definir interface después de que los tipos ya existan. Puedes crear una interface que coincida con tipos de paquetes externos sin modificar su código fuente. Los tipos no necesitan conocer tu interface. Solo necesitan comportarse correctamente.

El tipado pato en Go te brinda la flexibilidad de los lenguajes dinámicos, al tiempo que mantiene la seguridad de tipos en tiempo de compilación. El compilador verifica que los tipos realmente tengan los métodos necesarios antes de permitir que se utilicen como valores de interfaz.

challenge icon

Desafío

Fácil

Construyamos un sistema de mensajería que demuestre el tipado pato en acción. Crearás tipos completamente no relacionados que puedan enviar mensajes a través de una interfaz común, sin que ninguno declare explícitamente que la implementa.

Organizarás tu código en tres archivos:

  • messengers.go: Crea tres estructuras no relacionadas que casualmente comparten el mismo comportamiento:
    • Phone con un campo Number. Su método SendMessage(text string) string devuelve SMS to [Number]: [text]
    • Computer con un campo Email. Su método SendMessage(text string) string devuelve Email to [Email]: [text]
    • Pigeon con un campo Name. Su método SendMessage(text string) string devuelve [Name] carries: [text]
    Observa que ninguno de estos tipos menciona ninguna interfaz. Simplemente tienen la misma firma de método.
  • sender.go: Define una interfaz Messenger que requiera un método SendMessage(text string) string. Crea una función llamada Broadcast que reciba un slice de Messenger y un mensaje de tipo string, y después devuelva un slice de strings que contenga el resultado de llamar a SendMessage en cada mensajero.
  • main.go: Lee los datos de la entrada, crea uno de cada tipo de mensajero, los reúne en un slice de Messenger y usa Broadcast para enviar un mensaje a través de todos ellos. Imprime cada resultado en su propia línea.

Se proporcionarán las siguientes entradas:

  • Línea 1: Número de teléfono
  • Línea 2: Dirección de correo electrónico
  • Línea 3: Nombre de la paloma
  • Línea 4: Mensaje que se transmitirá

Por ejemplo, dados 555-1234, alice@mail.com, Winston y Hello World, tu salida debería ser:

SMS to 555-1234: Hello World
Email to alice@mail.com: Hello World
Winston carries: Hello World

La idea clave aquí es que Phone, Computer y Pigeon no tienen nada en común. No comparten un tipo base ni implementan explícitamente Messenger. Sin embargo, como todos "hacen cuac" de la misma manera (tienen el método correspondiente), Go permite que todos se utilicen como valores de tipo Messenger. Esto es el tipado pato en acción.

Pruébalo tú mismo

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Lee el número de teléfono
	scanner.Scan()
	phoneNumber := scanner.Text()
	
	// Read email address
	scanner.Scan()
	email := scanner.Text()
	
	// Lee el nombre de la paloma
	scanner.Scan()
	pigeonName := scanner.Text()
	
	// Lee el mensaje a transmitir
	scanner.Scan()
	message := scanner.Text()
	
	// TODO: Crea uno de cada tipo de mensajero (Phone, Computer, Pigeon)
	
	// TODO: Recolecta todos los mensajeros en un slice de Messenger
	
	// TODO: Usa Broadcast para enviar el mensaje a través de todos los mensajeros
	
	// TODO: Imprime cada resultado en su propia línea
	
	// Marcador de posición para usar las variables (eliminar al implementar)
	_ = phoneNumber
	_ = email
	_ = pigeonName
	_ = message
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Go online