Menu
Coddy logo textTech

Interfaces Stringer & Error

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 32 de 107.

A biblioteca padrão do Go define duas interfaces que você usará constantemente: fmt.Stringer e error. Ambas são interfaces simples de método único que dão aos seus tipos uma integração poderosa com a funcionalidade nativa do Go.

A interface Stringer reside no pacote fmt e requer apenas um método:

type Stringer interface {
    String() string
}

Quando você implementa String() em seu tipo, funções como fmt.Println automaticamente o utilizam para exibir seu valor:

type Person struct {
    Name string
    Age  int
}

func (p Person) String() string {
    return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

func main() {
    p := Person{Name: "Alice", Age: 30}
    fmt.Println(p)  // Alice (30 anos de idade)
}

A interface error é igualmente simples, exigindo um método Error() que retorna uma string:

type error interface {
    Error() string
}

Qualquer tipo com um método Error() pode ser usado como um valor de erro em Go. Isso permite que você crie tipos de erro personalizados com contexto adicional:

type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", e.Field, e.Message)
}

func main() {
    err := ValidationError{Field: "email", Message: "invalid format"}
    fmt.Println(err)  // email: invalid format
}

Estas duas interfaces demonstram a filosofia do Go: interfaces pequenas e focadas que desbloqueiam comportamentos poderosos através de implementação implícita.

challenge icon

Desafio

Fácil

Vamos construir um sistema de monitoramento de temperatura que utiliza as interfaces Stringer e error para fornecer uma saída legível e um tratamento de erros significativo.

Você organizará seu código em dois arquivos:

  • temperature.go: Crie uma struct Temperature com os campos Value (float64) e Unit (string). Implemente o método String() para que, quando impresso, exiba a temperatura em um formato legível por humanos. Também crie uma struct TemperatureError com os campos Temp (float64) e Reason (string), e implemente o método Error() para fornecer mensagens de erro descritivas.
  • main.go: Crie uma função chamada ValidateTemperature que recebe uma Temperature e retorna um erro se a temperatura for inválida. Uma temperatura é inválida se estiver abaixo do zero absoluto (-273.15 para Celsius, -459.67 para Fahrenheit). Se for válida, a função retorna nil. Leia os dados de temperatura da entrada, crie uma Temperature, valide-a e imprima a saída apropriada.

As seguintes entradas serão fornecidas:

  • Linha 1: Valor da temperatura (float)
  • Linha 2: Unidade (C para Celsius ou F para Fahrenheit)

Seu método String() deve retornar o formato:

[Value] degrees [Unit]

Onde Unit é a palavra completa "Celsius" ou "Fahrenheit" baseada na entrada.

Seu método Error() deve retornar o formato:

invalid temperature [Temp]: [Reason]

Se a temperatura for válida, imprima a Temperature usando fmt.Println (que usará seu método String()). Se for inválida, imprima o erro (que usará seu método Error()).

Por exemplo, dados 25.5 e C, sua saída deve ser:

25.5 degrees Celsius

Dados -500 e F, sua saída deve ser:

invalid temperature -500: below absolute zero

Use "below absolute zero" como a razão (reason) quando a temperatura for muito baixa.

Folha de consulta

A biblioteca padrão do Go define duas interfaces essenciais: fmt.Stringer e error.

A Interface Stringer

A interface Stringer do pacote fmt requer um método:

type Stringer interface {
    String() string
}

Quando você implementa String() no seu tipo, funções como fmt.Println o utilizam automaticamente:

type Person struct {
    Name string
    Age  int
}

func (p Person) String() string {
    return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

func main() {
    p := Person{Name: "Alice", Age: 30}
    fmt.Println(p)  // Alice (30 years old)
}

A Interface error

A interface error requer um método Error() que retorna uma string:

type error interface {
    Error() string
}

Qualquer tipo com um método Error() pode ser usado como um valor de erro, permitindo tipos de erro personalizados com contexto adicional:

type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", e.Field, e.Message)
}

func main() {
    err := ValidationError{Field: "email", Message: "invalid format"}
    fmt.Println(err)  // email: invalid format
}

Experimente você mesmo

package main

import (
	"fmt"
)

// ValidateTemperature verifica se uma temperatura é válida
// Retorna um erro se a temperatura estiver abaixo do zero absoluto
// Zero absoluto: -273.15 para Celsius, -459.67 para Fahrenheit
func ValidateTemperature(t Temperature) error {
	// TODO: Implementar lógica de validação
	// Verificar se a temperatura está abaixo do zero absoluto com base na unidade
	// Retornar um TemperatureError se for inválida, nil se for válida
	return nil
}

func main() {
	var value float64
	var unit string
	fmt.Scanln(&value)
	fmt.Scanln(&unit)

	// TODO: Criar uma struct Temperature com os valores de entrada

	// TODO: Validar a temperatura usando ValidateTemperature

	// TODO: Se houver um erro, imprimir o erro
	// Caso contrário, imprimir a temperatura (que usará o método String())
}
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