error 接口
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 52 课,共 107 课。
在 Go 中,错误通过一个名为 error 的内置接口来处理。这个接口非常简单,只要求实现一个方法:
type error interface {
Error() string
}任何实现了返回字符串的 Error() 方法的类型,都会自动满足 error 接口。这就是 Go 的接口系统在发挥作用:无需显式声明。
创建错误最常见的方法是使用 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
}Go 函数通常会将错误作为最后一个返回值。没有发生错误时,返回 nil。调用方会先检查错误是否非 nil,然后再继续:
result, err := Divide(10, 0)
if err != nil {
fmt.Println("Error:", err.Error())
return
}
fmt.Println("Result:", result)你也可以使用 fmt.Errorf 创建格式化的错误消息:
func GetUser(id int) (string, error) {
if id <= 0 {
return "", fmt.Errorf("invalid user id: %d", id)
}
return "Alice", nil
}这种返回错误而不是抛出异常的模式是 Go 的基础。它让错误处理变得明确,并促使你考虑出错时会发生什么,这是编写健壮的面向对象代码的关键。
挑战
简单让我们构建一个银行账户系统,展示 Go 的错误处理模式。你将创建一个简单的账户,用于验证操作,并在出错时返回有意义的错误。
你将把代码分成两个文件:
account.go:创建一个BankAccount结构体,包含一个已导出的Owner字段(string)和一个未导出的balance字段(float64)。实现以下内容:NewBankAccount(owner string, initialDeposit float64) (*BankAccount, error):一个构造函数。如果初始存款为零或负数,则返回错误,错误消息为"initial deposit must be positive"。否则,创建并返回账户。Deposit(amount float64) error:向余额中存入金额。如果金额为零或负数,则返回错误,错误消息为"deposit amount must be positive"。Withdraw(amount float64) error:从余额中取出金额。如果金额为零或负数,则返回错误,错误消息为"withdrawal amount must be positive";如果余额小于取款金额,则返回"insufficient funds"。Balance() float64:返回当前余额。
main.go:从输入中读取账户详情和交易金额。尝试创建账户并执行操作。每次操作后,打印成功消息或错误消息。
将提供以下输入:
- 第 1 行:账户所有者姓名
- 第 2 行:初始存款金额
- 第 3 行:存款金额
- 第 4 行:取款金额
对于每项操作,打印结果:
- 创建账户后:
Account created for [Owner] with balance: $[balance]或Error: [error message] - 存款后:
Deposited successfully. New balance: $[balance]或Error: [error message] - 取款后:
Withdrew successfully. New balance: $[balance]或Error: [error message]
所有余额值都保留两位小数。如果创建账户失败,则跳过剩余操作。
例如,输入 Alice、100、50 和 200 时,输出应为:
Account created for Alice with balance: $100.00
Deposited successfully. New balance: $150.00
Error: insufficient funds输入 Bob、-50、25 和 10 时,输出应为:
Error: initial deposit must be positive亲手试试
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// 读取账户持有人姓名
ownerName, _ := reader.ReadString('\n')
ownerName = strings.TrimSpace(ownerName)
// 读取初始存款
initialDepositStr, _ := reader.ReadString('\n')
initialDeposit, _ := strconv.ParseFloat(strings.TrimSpace(initialDepositStr), 64)
// 读取存款金额
depositStr, _ := reader.ReadString('\n')
depositAmount, _ := strconv.ParseFloat(strings.TrimSpace(depositStr), 64)
// 读取取款金额
withdrawStr, _ := reader.ReadString('\n')
withdrawAmount, _ := strconv.ParseFloat(strings.TrimSpace(withdrawStr), 64)
// TODO: 使用 NewBankAccount 创建一个新银行账户
// 如果出错,打印 "Error: [error message]" 并返回
// 如果成功,打印 "Account created for [Owner] with balance: $[balance]"
// TODO: 尝试存入指定金额
// 如果出错,打印 "Error: [error message]"
// 如果成功,打印 "Deposited successfully. New balance: $[balance]"
// TODO: 尝试取出指定金额
// 如果出错,打印 "Error: [error message]"
// 如果成功,打印 "Withdrew successfully. New balance: $[balance]"
// 记得使用 fmt.Printf("%.2f", balance) 将余额格式化为保留两位小数
_ = ownerName
_ = initialDeposit
_ = depositAmount
_ = withdrawAmount
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Go 在线编译器