Desafio Go

Formas geométricas com interface

Enunciado

Crie uma interface Forma com o método Area() float64. Implemente os tipos Retangulo (campos largura, altura float64) e Circulo (campo raio float64). Use receiver de valor para Area. No main, crie um slice de Forma com um retângulo e um círculo, e imprima a área de cada um.

Requisitos

  • Interface Forma com Area() float64
  • Retangulo e Circulo implementam Forma com receiver de valor
  • Slice []Forma contendo ambas as formas
  • Imprimir a área de cada forma com fmt.Printf

Código inicial

package main

import (
	"fmt"
	"math"
)

type Forma interface {
	Area() float64
}

// TODO: defina Retangulo e Circulo com Area()

func main() {
	// TODO: crie slice de Forma e imprima as áreas
}

Saída esperada

Retângulo: 24.00
Círculo: 78.54
Ver dica

Para o círculo, use math.Pi * raio * raio. O receiver de valor é suficiente porque só lemos campos.

Mostrar solução
package main

import (
	"fmt"
	"math"
)

type Forma interface {
	Area() float64
}

type Retangulo struct {
	largura, altura float64
}

// Receiver de valor: lê os campos sem modificar.
func (r Retangulo) Area() float64 {
	return r.largura * r.altura
}

type Circulo struct {
	raio float64
}

// Receiver de valor: lê o campo raio.
func (c Circulo) Area() float64 {
	return math.Pi * c.raio * c.raio
}

func main() {
	formas := []Forma{
		Retangulo{largura: 6, altura: 4},
		Circulo{raio: 5},
	}

	fmt.Printf("Retângulo: %.2f\n", formas[0].Area())
	fmt.Printf("Círculo: %.2f\n", formas[1].Area())
}

Passo a passo

  1. Declaramos a interface Forma com o método Area() float64.
  2. Definimos Retangulo com campos largura e altura.
  3. Implementamos Area com receiver de valor (r Retangulo), multiplicando os campos.
  4. Definimos Circulo com campo raio.
  5. Implementamos Area com receiver de valor (c Circulo), usando math.Pi * c.raio * c.raio.
  6. No main, criamos um slice []Forma com um Retangulo e um Circulo.
  7. Imprimimos as áreas com fmt.Printf e formato %.2f.

Por que funciona

Como Area tem receiver de valor, tanto Retangulo quanto Circulo (valores) satisfazem a interface Forma. O method set de Retangulo inclui Area, então Retangulo{...} pode ser atribuído a Forma. O slice armazena valores que implementam a interface, e a chamada formas[i].Area() é resolvida dinamicamente.

Erros comuns

  • Usar receiver de ponteiro em Area e tentar atribuir valor a Forma: Retangulo{...} não implementa Forma se Area for func (r *Retangulo) Area(). Seria necessário usar &Retangulo{...}.
  • Esquecer de importar math: erro de compilação ao usar math.Pi.
  • Formatar com %d em vez de %.2f: saída incorreta ou erro de formatação.

Outra forma de resolver

Poderia usar receiver de ponteiro e armazenar ponteiros no slice: []Forma{&Retangulo{...}, &Circulo{...}}. Isso é preferível se os métodos precisarem modificar o estado ou se os structs forem grandes.

Saída esperada

Retângulo: 24.00
Círculo: 78.54