Desafio Go

Módulo com múltiplos pacotes e internal

Enunciado

Crie um módulo exemplo.com/empresa com a seguinte estrutura:

  • Pacote funcionarios (em funcionarios/) que exporte a struct Funcionario com campos Nome (string) e Salario (float64), e uma função NovoFuncionario(nome string, salario float64) Funcionario.
  • Pacote internal/folha (em internal/folha/) que exporte a função CalcularTotal(funcs []funcionarios.Funcionario) float64.
  • main.go que cria dois funcionários, calcula o total da folha e imprime no formato Total da folha: R$ 7500.00.

Use valores: Ana com 5000.00 e Bruno com 2500.00.

Requisitos

  • O módulo deve se chamar exemplo.com/empresa.
  • O pacote funcionarios deve estar em funcionarios/ e exportar Funcionario e NovoFuncionario.
  • O pacote folha deve estar em internal/folha/ e importar funcionarios.
  • A saída deve ser exatamente Total da folha: R$ 7500.00.

Código inicial

// main.go
package main

import (
	"fmt"
	// importe os pacotes necessários
)

func main() {
	// crie os funcionários e calcule o total
	fmt.Println("Total da folha: R$ 0.00") // substitua
}

Saída esperada

Total da folha: R$ 7500.00
Ver dica

No pacote folha, você precisará importar exemplo.com/empresa/funcionarios. A função CalcularTotal percorre a slice e soma os salários. Use fmt.Printf com R$ %.2f.

Mostrar solução
// go.mod
module exemplo.com/empresa

go 1.22
// funcionarios/funcionarios.go
package funcionarios

// Funcionario representa um empregado.
type Funcionario struct {
	Nome    string
	Salario float64
}

// NovoFuncionario cria um Funcionario com os dados fornecidos.
func NovoFuncionario(nome string, salario float64) Funcionario {
	return Funcionario{Nome: nome, Salario: salario}
}
// internal/folha/folha.go
package folha

import "exemplo.com/empresa/funcionarios"

// CalcularTotal soma os salários de uma lista de funcionários.
func CalcularTotal(funcs []funcionarios.Funcionario) float64 {
	total := 0.0
	for _, f := range funcs {
		total += f.Salario
	}
	return total
}
// main.go
package main

import (
	"fmt"
	"exemplo.com/empresa/funcionarios"
	"exemplo.com/empresa/internal/folha"
)

func main() {
	ana := funcionarios.NovoFuncionario("Ana", 5000.00)
	bruno := funcionarios.NovoFuncionario("Bruno", 2500.00)
	total := folha.CalcularTotal([]funcionarios.Funcionario{ana, bruno})
	fmt.Printf("Total da folha: R$ %.2f\n", total)
}

Passo a passo

  1. Criamos o módulo com go mod init exemplo.com/empresa.
  2. No pacote funcionarios, definimos a struct Funcionario com campos exportados Nome e Salario.
  3. A função NovoFuncionario é um construtor que retorna uma instância de Funcionario.
  4. No pacote internal/folha, importamos exemplo.com/empresa/funcionarios (permitido porque estamos dentro do módulo).
  5. CalcularTotal percorre a slice de funcionários e soma os salários.
  6. No main.go, criamos dois funcionários com NovoFuncionario e os colocamos em uma slice.
  7. Chamamos folha.CalcularTotal passando a slice e armazenamos o resultado.
  8. Imprimimos com fmt.Printf usando R$ %.2f para formatar o valor.

Por que funciona

A estrutura de pastas define pacotes separados: funcionarios e internal/folha. O pacote folha está em internal, então só pode ser importado por código dentro do módulo exemplo.com/empresa. Como main.go está na raiz, pode importá-lo. A comunicação entre pacotes usa tipos exportados: folha importa funcionarios e usa funcionarios.Funcionario como tipo de parâmetro. O compilador verifica se todos os identificadores usados são exportados e se os imports são válidos.

Erros comuns

  • Esquecer de exportar campos da struct: se Funcionario tivesse campos nome e salario (minúsculos), o pacote folha não conseguiria acessá-los. Erro: f.Salario undefined (cannot refer to unexported field or method salario).
  • Import cycle: se funcionarios importasse folha e vice-versa, o compilador acusaria ciclo de importação. A solução é manter dependências em uma direção só.
  • Caminho de import errado: usar import "empresa/funcionarios" em vez de exemplo.com/empresa/funcionarios. O Go não encontra o pacote.
  • Não usar internal corretamente: se folha estivesse fora de internal, ainda funcionaria, mas perderia a restrição de acesso.

Outra forma de resolver

Se não precisasse restringir o acesso, folha poderia ficar em folha/ diretamente. O uso de internal é uma escolha de design para esconder detalhes de implementação. Também é possível usar um método Total() na struct, mas a função separada demonstra melhor a interação entre pacotes.

Saída esperada

Total da folha: R$ 7500.00