Passagem por Valor vs. Referência
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 21 de 107.
Go é uma linguagem de passagem por valor. Quando você passa uma variável para uma função, o Go cria uma cópia desse valor. Isso significa que alterações dentro da função não afetam a variável original.
func double(n int) {
n = n * 2
}
func main() {
x := 10
double(x)
fmt.Println(x) // 10 (inalterado)
}O mesmo se aplica às structs. Passar uma struct para uma função copia todos os seus campos, portanto as modificações feitas dentro da função são perdidas.
type Person struct {
Name string
Age int
}
func birthday(p Person) {
p.Age++
}
func main() {
alice := Person{Name: "Alice", Age: 30}
birthday(alice)
fmt.Println(alice.Age) // 30 (inalterado)
}Para modificar o valor original, passe um ponteiro em vez disso. O ponteiro em si é copiado, mas ele ainda aponta para o mesmo endereço de memória, permitindo que você altere os dados originais.
func birthday(p *Person) {
p.Age++
}
func main() {
alice := Person{Name: "Alice", Age: 30}
birthday(&alice)
fmt.Println(alice.Age) // 31 (modificado!)
}Use ponteiros quando precisar modificar o valor original ou ao passar structs grandes para evitar cópias dispendiosas. Use valores quando quiser proteger os dados originais de alterações indesejadas.
Desafio
FácilVamos criar um sistema de carrinho de compras que demonstra a diferença entre passar structs por valor e por ponteiro. Você verá na prática como somente parâmetros de ponteiro podem modificar os dados originais.
Você organizará seu código em dois arquivos:
cart.go: Defina uma structCartItemcom camposName(string),Price(float64) eQuantity(int). Crie duas funções que tentam atualizar a quantidade:UpdateQuantityByValuerecebe umCartItem(por valor) e uma nova quantidade, então define a quantidade do item como o novo valorUpdateQuantityByPointerrecebe um*CartItem(ponteiro) e uma nova quantidade, então define a quantidade do item como o novo valor
TotalemCartItemque retorna o preço multiplicado pela quantidade.main.go: Leia os detalhes do item da entrada, crie um CartItem e demonstre ambas as abordagens de atualização. Primeiro, tente atualizar usando a função que recebe o valor e mostre o resultado; em seguida, atualize usando a função que recebe o ponteiro e mostre o resultado novamente.
As entradas a seguir serão fornecidas:
- Linha 1: Nome do item
- Linha 2: Preço (float)
- Linha 3: Quantidade inicial (inteiro)
- Linha 4: Nova quantidade a ser definida (inteiro)
Formato da saída:
Initial: [Name] x[Quantity] = $[Total]
After value update: [Name] x[Quantity] = $[Total]
After pointer update: [Name] x[Quantity] = $[Total]Por exemplo, dadas as entradas Laptop, 999.99, 1 e 3, sua saída deverá ser:
Initial: Laptop x1 = $999.99
After value update: Laptop x1 = $999.99
After pointer update: Laptop x3 = $2999.97Observe como a quantidade permanece em 1 após a atualização por valor (a função modificou uma cópia), mas muda para 3 após a atualização por ponteiro (a função modificou o original). Formate os totais com duas casas decimais.
Experimente você mesmo
package main
import (
"fmt"
)
func main() {
// Ler entrada
var name string
var price float64
var initialQty, newQty int
fmt.Scanln(&name)
fmt.Scanln(&price)
fmt.Scanln(&initialQty)
fmt.Scanln(&newQty)
// TODO: Criar um CartItem com os valores de entrada
// TODO: Imprimir o estado inicial usando o formato:
// fmt.Printf("Initial: %s x%d = $%.2f\n", ...)
// TODO: Tentar atualizar a quantidade usando UpdateQuantityByValue
// Em seguida, imprimir o resultado (observe que a quantidade não mudará)
// TODO: Atualizar a quantidade usando UpdateQuantityByPointer
// Em seguida, imprimir o resultado (observe que a quantidade mudará)
}
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