Noções básicas de incorporação de structs
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 35 de 107.
Incorporação de structs é o mecanismo do Go para incluir um tipo struct dentro de outro. Em vez de usar um nome de campo, você simplesmente especifica o tipo, e o Go promove os campos da struct incorporada para a struct externa.
Aqui está a sintaxe básica:
type Address struct {
City string
Country string
}
type Person struct {
Name string
Address // embutido - sem nome de campo
}
Quando você incorpora Address em Person, pode acessar os campos incorporados diretamente na struct externa:
func main() {
p := Person{
Name: "Alice",
Address: Address{
City: "London",
Country: "UK",
},
}
fmt.Println(p.City) // London - acesso direto
fmt.Println(p.Country) // UK - acesso direto
fmt.Println(p.Address.City) // também funciona
}
Observe como p.City funciona sem escrever explicitamente p.Address.City. O Go promove automaticamente os campos da struct incorporada, tornando-os acessíveis como se pertencessem à struct externa. Você ainda pode acessá-los por meio do nome do tipo incorporado quando necessário.
Isso difere das estruturas aninhadas comuns, nas quais você sempre precisa usar o nome do campo para acessar os campos internos. A incorporação cria uma API mais plana e conveniente, mantendo ainda o agrupamento lógico de dados relacionados.
Desafio
FácilVamos criar um sistema de registro de veículos que usa incorporação de structs para criar um modelo de dados limpo e organizado. Você separará as informações de contato dos detalhes do veículo, permitindo acesso direto a todos os campos por meio da incorporação.
Você organizará seu código em dois arquivos:
vehicle.go: Crie duas structs que trabalham juntas por meio da incorporação:- Uma struct
ContactInfocom os camposOwnerNameePhone(ambos strings) - Uma struct
Vehicleque incorporaContactInfo(sem um nome de campo) e adiciona seus próprios camposMake,ModeleYear
SummaryemVehicleque retorne uma string formatada contendo todas as informações do veículo e do contato.- Uma struct
main.go: Leia os detalhes do veículo e do proprietário da entrada, crie uma instância deVehiclecomContactInfoincorporada e demonstre o acesso aos campos incorporados tanto diretamente quanto por meio do nome do tipo incorporado. Imprima o resumo do veículo ao final.
As seguintes entradas serão fornecidas:
- Linha 1: Nome do proprietário
- Linha 2: Número de telefone
- Linha 3: Marca do veículo
- Linha 4: Modelo do veículo
- Linha 5: Ano (inteiro)
Seu método Summary deve retornar uma string neste formato:
[Year] [Make] [Model] - Owner: [OwnerName], Phone: [Phone]Em seu arquivo principal, demonstre a promoção de campos imprimindo:
- O nome do proprietário acessado diretamente em Vehicle (por exemplo,
v.OwnerName) - O telefone acessado por meio do tipo incorporado (por exemplo,
v.ContactInfo.Phone) - O resumo completo do seu método
Summary
Por exemplo, considerando Alice Smith, 555-1234, Toyota, Camry e 2023, sua saída deve ser:
Alice Smith
555-1234
2023 Toyota Camry - Owner: Alice Smith, Phone: 555-1234Observe como os dois padrões de acesso funcionam: o acesso direto por meio da promoção de campos e o acesso explícito por meio do nome do tipo incorporado, oferecendo flexibilidade na forma como você trabalha com dados incorporados.
Experimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Ler o nome do proprietário
ownerName, _ := reader.ReadString('\n')
ownerName = strings.TrimSpace(ownerName)
// Ler o número de telefone
phone, _ := reader.ReadString('\n')
phone = strings.TrimSpace(phone)
// Ler a marca do veículo
make, _ := reader.ReadString('\n')
make = strings.TrimSpace(make)
// Ler o modelo do veículo
model, _ := reader.ReadString('\n')
model = strings.TrimSpace(model)
// Ler o ano
yearStr, _ := reader.ReadString('\n')
yearStr = strings.TrimSpace(yearStr)
year, _ := strconv.Atoi(yearStr)
// TODO: Crie uma instância de Vehicle com ContactInfo embutido
// Use os valores lidos da entrada acima
// TODO: Imprima o nome do proprietário acessado diretamente no Vehicle (promoção de campo)
// Exemplo: fmt.Println(v.OwnerName)
// TODO: Imprima o telefone acessado através do nome do tipo embutido
// Exemplo: fmt.Println(v.ContactInfo.Phone)
// TODO: Imprima o resumo completo usando o método Summary
// Exemplo: fmt.Println(v.Summary())
// Remova estas linhas assim que implementar a solução
_ = ownerName
_ = phone
_ = make
_ = model
_ = year
}
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