Campos Exportados vs Não Exportados
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 47 de 107.
Em Go, o encapsulamento no nível da struct é controlado pela capitalização dos nomes dos campos. Essa regra simples determina se os campos podem ser acessados de fora do pacote onde a struct está definida.
Campos que começam com uma letra maiúscula são exportados—acessíveis a partir de qualquer pacote. Campos que começam com uma letra minúscula não são exportados—acessíveis apenas dentro do mesmo pacote:
// No pacote "user"
type User struct {
Name string // Exportado - acessível em qualquer lugar
Email string // Exportado - acessível em qualquer lugar
password string // Não exportado - acessível apenas no pacote "user"
age int // Não exportado - acessível apenas no pacote "user"
}
Quando outro pacote importa e usa esta struct, ele só pode interagir com campos exportados:
// No pacote "main"
import "user"
func main() {
u := user.User{
Name: "Alice", // funciona
Email: "a@mail.com", // funciona
// password: "secret", // erro de compilação: campo desconhecido
}
fmt.Println(u.Name) // funciona
// fmt.Println(u.password) // erro de compilação: não é possível referenciar um campo não exportado
}
Este mecanismo protege dados sensíveis e detalhes de implementação interna. O campo password não pode ser lido ou modificado diretamente de fora do pacote, forçando outros códigos a usarem métodos que você fornece. Esta é a abordagem do Go para alcançar a ocultação de dados — um princípio fundamental do encapsulamento na programação orientada a objetos.
Desafio
FácilVamos construir um sistema de conta bancária que demonstra o encapsulamento por meio de campos exportados e não exportados. Você criará um pacote que protege dados financeiros sensíveis enquanto expõe informações públicas seguras.
Você organizará seu código em dois arquivos:
account.go: Crie uma structBankAccountno pacotemainque modele uma conta bancária real com a devida proteção de dados:HolderName(exportado) - o nome do titular da conta, seguro para exibição públicaAccountType(exportado) - o tipo de conta (ex: "Savings", "Checking")balance(não exportado) - o saldo real, que deve ser protegidopin(não exportado) - o PIN da conta, um dado altamente sensível
NewBankAccountque receba o nome do titular, o tipo de conta, o saldo inicial e o PIN, e retorne um ponteiro para um novoBankAccount. Adicione também um métodoGetPublicInfo() stringque retorne o formato:Account: [HolderName] ([AccountType])main.go: Leia os detalhes da conta da entrada, crie umBankAccountusando o construtor e demonstre o encapsulamento. Imprima as informações públicas usando o método e, em seguida, acesse e imprima diretamente cada campo exportado em linhas separadas. Os campos não exportados (balanceepin) estão protegidos — você só pode defini-los através do construtor.
As seguintes entradas serão fornecidas:
- Linha 1: Nome do titular da conta
- Linha 2: Tipo de conta
- Linha 3: Saldo inicial (como um float)
- Linha 4: Código PIN
Por exemplo, dados Alice Johnson, Savings, 5000.50 e 1234, sua saída deve ser:
Account: Alice Johnson (Savings)
Holder: Alice Johnson
Type: SavingsObserve que o saldo e o PIN nunca aparecem na saída — eles estão ocultos com segurança dentro da struct, acessíveis apenas dentro do pacote. Isso é o encapsulamento em ação: dados sensíveis são protegidos enquanto as informações públicas permanecem acessíveis.
Folha de consulta
Em Go, o encapsulamento é controlado pela capitalização dos nomes dos campos em structs:
- Campos em maiúsculo são exportados (acessíveis de qualquer pacote)
- Campos em minúsculo não são exportados (acessíveis apenas dentro do mesmo pacote)
type User struct {
Name string // Exportado - acessível em qualquer lugar
Email string // Exportado - acessível em qualquer lugar
password string // Não exportado - acessível apenas no mesmo pacote
age int // Não exportado - acessível apenas no mesmo pacote
}
Ao usar uma struct de outro pacote, apenas os campos exportados são acessíveis:
import "user"
func main() {
u := user.User{
Name: "Alice", // funciona
Email: "a@mail.com", // funciona
// password: "secret", // erro de compilação: campo desconhecido
}
fmt.Println(u.Name) // funciona
// fmt.Println(u.password) // erro de compilação: não é possível referenciar um campo não exportado
}
Este mecanismo protege dados sensíveis e detalhes de implementação interna, forçando o código externo a usar os métodos fornecidos para acesso.
Experimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Ler o nome do titular da conta
holderName, _ := reader.ReadString('\n')
holderName = strings.TrimSpace(holderName)
// Ler o tipo de conta
accountType, _ := reader.ReadString('\n')
accountType = strings.TrimSpace(accountType)
// Ler o saldo inicial
balanceStr, _ := reader.ReadString('\n')
balanceStr = strings.TrimSpace(balanceStr)
balance, _ := strconv.ParseFloat(balanceStr, 64)
// Ler o PIN
pinStr, _ := reader.ReadString('\n')
pin := strings.TrimSpace(pinStr)
// TODO: Criar um novo BankAccount usando o construtor
// account := NewBankAccount(...)
// TODO: Imprimir as informações públicas usando o método GetPublicInfo()
// TODO: Imprimir o nome do titular acessando diretamente o campo exportado
// fmt.Println("Holder:", ...)
// TODO: Imprimir o tipo de conta acessando diretamente o campo exportado
// fmt.Println("Type:", ...)
// Note: balance e pin não são exportados - eles não podem ser acessados diretamente aqui
// Eles estão encapsulados com segurança dentro da struct
_ = balance // Remova esta linha quando você usar balance
_ = pin // Remova esta linha quando você usar pin
}
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
1Fundamentos de OOP em Go
Arquivos ExternosGo Workspace e MódulosPacotes e ImportaçõesNomes Exportados vs Não ExportadosIntrodução a OOP em GoStructs como ClassesDefinindo Métodos em StructsRecebedores de Ponteiro vs ValorInicialização de StructsFunções ConstrutorasRecapitulação - Calculadora Simples4Interfaces
Introdução a InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Type AssertionType SwitchComposição de InterfacesInterfaces Stringer & ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs Não ExportadosEncapsulamento em Nível de PacoteMétodos Getter e SetterOcultação de Informação em GoRecapitulação - Registros de Estudantes10Generics (Go 1.18+)
Introdução a GenericsParâmetros de TipoRestrições de TipoStructs GenéricasSolução Alternativa para Métodos GenéricosRecapitulação - Coleção Genérica2Mergulho Profundo em Tipos e Structs
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosStruct TagsStructs AnônimasStructs AninhadasZero Values e PadrõesRecapitulação - Agenda de Contatos5Composição em vez de Herança
Por que Go não possui HerançaFundamentos de Incorporação de StructsPromoção de MétodosIncorporando Múltiplas StructsIncorporação vs AgregaçãoShadowing de Métodos IncorporadosRecapitulação - Hierarquia de Funcionários8Tratamento de Erros e OOP
A Interface errorTipos de Erro PersonalizadosError Wrapping (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - File Parser3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs ReferênciaA Função new()Garbage Collection em GoRecapitulação - Construtor de Lista Encadeada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfaceColeções PolimórficasInjeção de DependênciaRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e ComunicaçãoCanais com Buffer vs. Sem BufferInstrução Selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de Structs Thread-SafeRecapitulação - Worker Pool