A interface error
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 52 de 107.
Em Go, os erros são tratados por meio de uma interface integrada chamada error. Essa interface é notavelmente simples. Ela exige apenas um método:
type error interface {
Error() string
}Qualquer tipo que implemente um método Error() que retorne uma string satisfaz automaticamente a interface error. Este é o sistema de interfaces do Go em ação: nenhuma declaração explícita é necessária.
A maneira mais comum de criar erros é usando o pacote errors:
import "errors"
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("cannot divide by zero")
}
return a / b, nil
}As funções Go normalmente retornam um erro como seu último valor de retorno. Quando nenhum erro ocorre, você retorna nil. Em seguida, o chamador verifica se o erro é diferente de nil antes de prosseguir:
result, err := Divide(10, 0)
if err != nil {
fmt.Println("Error:", err.Error())
return
}
fmt.Println("Result:", result)Você também pode usar fmt.Errorf para criar mensagens de erro formatadas:
func GetUser(id int) (string, error) {
if id <= 0 {
return "", fmt.Errorf("invalid user id: %d", id)
}
return "Alice", nil
}Esse padrão de retornar erros em vez de lançar exceções é fundamental em Go. Ele torna o tratamento de erros explícito e obriga você a considerar o que acontece quando as coisas dão errado: um aspecto essencial da escrita de código robusto e orientado a objetos.
Desafio
FácilVamos criar um sistema de conta bancária que demonstra o padrão de tratamento de erros do Go. Você criará uma conta simples que valida as operações e retorna erros significativos quando algo dá errado.
Você organizará seu código em dois arquivos:
account.go: Crie uma structBankAccountcom um campo exportadoOwner(string) e um campo não exportadobalance(float64). Implemente o seguinte:NewBankAccount(owner string, initialDeposit float64) (*BankAccount, error)- um construtor que retorna um erro com a mensagem"initial deposit must be positive"se o depósito inicial for zero ou negativo. Caso contrário, crie e retorne a conta.Deposit(amount float64) error- adiciona dinheiro ao saldo. Retorne um erro com a mensagem"deposit amount must be positive"se o valor for zero ou negativo.Withdraw(amount float64) error- remove dinheiro do saldo. Retorne um erro com a mensagem"withdrawal amount must be positive"se o valor for zero ou negativo, ou"insufficient funds"se o saldo for menor que o valor do saque.Balance() float64- retorna o saldo atual
main.go: Leia os detalhes da conta e os valores das transações da entrada. Tente criar uma conta e realizar as operações. Após cada operação, imprima a mensagem de sucesso ou a mensagem de erro.
As seguintes entradas serão fornecidas:
- Linha 1: Nome do proprietário
- Linha 2: Valor do depósito inicial
- Linha 3: Valor do depósito
- Linha 4: Valor do saque
Para cada operação, imprima o resultado:
- Após a criação da conta:
Account created for [Owner] with balance: $[balance]ouError: [error message] - Após o depósito:
Deposited successfully. New balance: $[balance]ouError: [error message] - Após o saque:
Withdrew successfully. New balance: $[balance]ouError: [error message]
Formate todos os valores de saldo com duas casas decimais. Se a criação da conta falhar, ignore as operações restantes.
Por exemplo, dados Alice, 100, 50 e 200, sua saída deverá ser:
Account created for Alice with balance: $100.00
Deposited successfully. New balance: $150.00
Error: insufficient fundsE dados Bob, -50, 25 e 10, sua saída deverá ser:
Error: initial deposit must be positiveExperimente 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)
// Read initial deposit
initialDepositStr, _ := reader.ReadString('\n')
initialDeposit, _ := strconv.ParseFloat(strings.TrimSpace(initialDepositStr), 64)
// Read deposit amount
depositStr, _ := reader.ReadString('\n')
depositAmount, _ := strconv.ParseFloat(strings.TrimSpace(depositStr), 64)
// Read withdrawal amount
withdrawStr, _ := reader.ReadString('\n')
withdrawAmount, _ := strconv.ParseFloat(strings.TrimSpace(withdrawStr), 64)
// TODO: Criar uma nova conta bancária usando NewBankAccount
// Se houver um erro, imprima "Error: [error message]" e retorne
// Se bem-sucedido, imprima "Account created for [Owner] with balance: $[balance]"
// TODO: Tentar depositar o valor do depósito
// Se houver um erro, imprima "Error: [error message]"
// If successful, print "Deposited successfully. New balance: $[balance]"
// TODO: Tentar sacar o valor do saque
// Se houver um erro, imprima "Error: [error message]"
// If successful, print "Withdrew successfully. New balance: $[balance]"
// Lembre-se de formatar os valores de saldo com duas casas decimais usando fmt.Printf("%.2f", balance)
_ = ownerName
_ = initialDeposit
_ = depositAmount
_ = withdrawAmount
}
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