Menu
Coddy logo textTech

Duck Typing em Go

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 42 de 107.

O termo duck typing vem do ditado: "Se anda como um pato e grasna como um pato, então é um pato." Em Go, isso significa que um tipo não precisa declarar explicitamente que implementa uma interface. Ele só precisa ter os métodos corretos.

Considere esta interface e dois tipos completamente não 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!" }

Nem Duck nem Robot mencionam Quacker em nenhum lugar de suas definições. Ainda assim, ambos satisfazem a interface simplesmente porque têm um método Quack() com a assinatura correta:

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

func main() {
    MakeItQuack(Duck{})   // Quá!
    MakeItQuack(Robot{})  // Bip-quá!
}

Essa satisfação implícita é poderosa porque permite definir interfaces depois que os tipos já existem. Você pode criar uma interface que corresponda a tipos de pacotes externos sem modificar o código-fonte deles. Os tipos não precisam conhecer sua interface. Eles só precisam se comportar corretamente.

A tipagem pato em Go oferece a flexibilidade das linguagens dinâmicas, mantendo a segurança de tipos em tempo de compilação. O compilador verifica se os tipos realmente têm os métodos necessários antes de permitir que sejam usados como valores de interface.

challenge icon

Desafio

Fácil

Vamos construir um sistema de mensagens que demonstra a tipagem pato em ação. Você criará tipos completamente não relacionados que podem enviar mensagens por meio de uma interface comum, sem que nenhum deles declare explicitamente que a implementa.

Você organizará seu código em três arquivos:

  • messengers.go: Crie três structs não relacionadas que, por acaso, compartilham o mesmo comportamento:
    • Phone com um campo Number. Seu método SendMessage(text string) string retorna SMS to [Number]: [text]
    • Computer com um campo Email. Seu método SendMessage(text string) string retorna Email to [Email]: [text]
    • Pigeon com um campo Name. Seu método SendMessage(text string) string retorna [Name] carries: [text]
    Observe que nenhum desses tipos menciona qualquer interface. Eles apenas têm a mesma assinatura de método.
  • sender.go: Defina uma interface Messenger que exige um método SendMessage(text string) string. Crie uma função chamada Broadcast que receba um slice de Messenger e uma string de mensagem, depois retorne um slice de strings contendo o resultado da chamada de SendMessage em cada mensageiro.
  • main.go: Leia os dados da entrada, crie um mensageiro de cada tipo, reúna-os em um slice de Messenger e use Broadcast para enviar uma mensagem por meio de todos eles. Imprima cada resultado em sua própria linha.

As seguintes entradas serão fornecidas:

  • Linha 1: Número de telefone
  • Linha 2: Endereço de e-mail
  • Linha 3: Nome do pombo
  • Linha 4: Mensagem para transmitir

Por exemplo, dados 555-1234, alice@mail.com, Winston e Hello World, sua saída deve ser:

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

A principal ideia aqui é que Phone, Computer e Pigeon não têm nada em comum. Eles não compartilham um tipo base nem implementam explicitamente Messenger. No entanto, como todos eles "grasnam" da mesma forma (possuem o método correspondente), Go permite que todos sejam usados como valores de Messenger. Isso é a tipagem pato em ação.

Experimente você mesmo

package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Ler número de telefone
	scanner.Scan()
	phoneNumber := scanner.Text()
	
	// Read email address
	scanner.Scan()
	email := scanner.Text()
	
	// Ler nome do pombo
	scanner.Scan()
	pigeonName := scanner.Text()
	
	// Ler mensagem para transmitir
	scanner.Scan()
	message := scanner.Text()
	
	// TODO: Crie um de cada tipo de mensageiro (Phone, Computer, Pigeon)
	
	// TODO: Colete todos os mensageiros em um slice de Messenger
	
	// TODO: Use Broadcast para enviar a mensagem por todos os mensageiros
	
	// TODO: Imprima cada resultado em sua própria linha
	
	// Placeholder para usar as variáveis (remover ao implementar)
	_ = phoneNumber
	_ = email
	_ = pigeonName
	_ = message
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Go online