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 pelo uso de maiúsculas ou minúsculas nos nomes dos campos. Essa regra simples determina se os campos podem ser acessados de fora do pacote onde a struct é 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 são não exportados: acessíveis apenas dentro do mesmo pacote:
// No pacote "user"
type User struct {
Name string // Exportado - acessível em todos os lugares
Email string // Exportado - acessível em todos os lugares
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 essa estrutura, 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 campo não exportado
}
Esse mecanismo protege dados confidenciais e detalhes internos da implementação. O campo password não pode ser lido ou modificado diretamente de fora do pacote, obrigando outro código a usar os métodos que você fornece. Essa é a abordagem do Go para alcançar a ocultação de dados: um princípio fundamental da encapsulação na programação orientada a objetos.
Desafio
FácilVamos criar um sistema de conta bancária que demonstra encapsulamento por meio de campos exportados e não exportados. Você criará um pacote que protege dados financeiros confidenciais 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 proteção adequada dos dados:HolderName(exportado) - o nome do titular da conta, seguro para exibição públicaAccountType(exportado) - o tipo de conta (por exemplo, "Savings", "Checking")balance(não exportado) - o saldo real, que deve ser protegidopin(não exportado) - o PIN da conta, um dado altamente confidencial
NewBankAccountque receba o nome do titular, o tipo de conta, o saldo inicial e o PIN, e então retorne um ponteiro para uma novaBankAccount. Adicione também um métodoGetPublicInfo() stringque retorne o formato:Account: [HolderName] ([AccountType])main.go: Leia os dados da conta da entrada, crie umaBankAccountusando a função construtora 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) são protegidos. Você só pode defini-los por meio da função construtora.
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 deverá ser:
Account: Alice Johnson (Savings)
Holder: Alice Johnson
Type: SavingsObserve que o saldo e o PIN nunca aparecem na saída: eles ficam ocultos com segurança dentro da struct, acessíveis somente dentro do pacote. Isso é o encapsulamento em ação: os dados confidenciais são protegidos enquanto as informações públicas permanecem acessíveis.
Experimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Leia o nome do titular da conta
holderName, _ := reader.ReadString('\n')
holderName = strings.TrimSpace(holderName)
// Leia o tipo de conta
accountType, _ := reader.ReadString('\n')
accountType = strings.TrimSpace(accountType)
// Leia o saldo inicial
balanceStr, _ := reader.ReadString('\n')
balanceStr = strings.TrimSpace(balanceStr)
balance, _ := strconv.ParseFloat(balanceStr, 64)
// Leia o PIN
pinStr, _ := reader.ReadString('\n')
pin := strings.TrimSpace(pinStr)
// TODO: Crie um novo BankAccount usando o construtor
// account := NewBankAccount(...)
// TODO: Imprima as informações públicas usando o método GetPublicInfo()
// TODO: Imprima o nome do titular acessando diretamente o campo exportado
// fmt.Println("Holder:", ...)
// TODO: Imprima o tipo de conta acessando diretamente o campo exportado
// fmt.Println("Type:", ...)
// Note: balance e pin são unexported - 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 ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa para métodos genéricosRecapitulação - Coleção genérica13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker PoolPratique por conta própria: Compilador de Go online