2.4【函数结构】Go 函数定义与数据结构应用
2.4【函数特性】Go 函数定义与高级特性
Go 函数定义与数据结构应用
目录
Go 函数
1. 函数基础语法
基本函数定义
函数语法结构
// 完整的函数语法结构
func functionName(parameter1 type1, parameter2 type2, ...) (returnType1, returnType2, ...) {
// 函数体
// 局部变量声明
// 业务逻辑处理
return value1, value2, ...
}
函数的组成部分详解
1. 关键字 func
// func 是Go语言定义函数的关键字,所有函数都必须以 func 开头
func sayHello() {
fmt.Println("Hello, World!")
}
2. 函数名命名规则
// 函数名必须以字母或下划线开头,后面可以跟字母、数字或下划线
func calculateSum() int { return 0 } // 驼峰命名法(推荐)
func calculate_sum() int { return 0 } // 下划线命名法
func Calculate() int { return 0 } // 大写开头表示公开函数
func _privateFunc() int { return 0 } // 下划线开头的私有函数
// 无效的函数名
// func 123func() {} // 不能以数字开头
// func func-name() {} // 不能包含连字符
3. 参数详解
// 无参数函数
func getCurrentTime() string {
return time.Now().Format("2006-01-02 15:04:05")
}
// 单个参数
func square(x int) int {
return x * x
}
// 多个相同类型参数(简化写法)
func add(a, b int) int { // a int, b int 的简化写法
return a + b
}
// 多个不同类型参数
func formatUser(name string, age int, salary float64) string {
return fmt.Sprintf("Name: %s, Age: %d, Salary: %.2f", name, age, salary)
}
// 参数类型混合
func processData(id int, name string, active bool, scores []int) string {
status := "inactive"
if active {
status = "active"
}
return fmt.Sprintf("User %d: %s (%s) - %d scores", id, name, status, len(scores))
}
4. 返回值详解
// 无返回值函数
func printMessage(msg string) {
fmt.Println(msg)
// 隐式 return,等价于 return
}
// 单个返回值
func getLength(s string) int {
return len(s)
}
// 多个返回值(常用于错误处理)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
// 返回不同类型的多个值
func getUserInfo(id int) (string, int, bool, error) {
// 模拟数据库查询
if id <= 0 {
return "", 0, false, errors.New("invalid user ID")
}
return "Alice", 25, true, nil // name, age, active, error
}
实际应用示例
1. 数学计算函数
// 基本算术运算
func add(a, b int) int {
return a + b
}
func subtract(a, b int) int {
return a - b
}
func multiply(a, b int) int {
return a * b
}
func divide(a, b int) (int, int, error) {
if b == 0 {
return 0, 0, errors.New("除数不能为零")
}
quotient := a / b // 商
remainder := a % b // 余数
return quotient, remainder, nil
}
// 使用示例
func mathExample() {
x, y := 10, 3
sum := add(x, y)
fmt.Printf("%d + %d = %d\n", x, y, sum)
q, r, err := divide(x, y)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("%d ÷ %d = %d 余 %d\n", x, y, q, r)
}
}
2. 字符串处理函数
// 字符串操作函数
func reverseString(s string) string {
runes := []rune(s) // 支持中文字符
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
func countWords(text string) int {
words := strings.Fields(text) // 按空白字符分割
return len(words)
}
func capitalizeFirst(s string) string {
if len(s) == 0 {
return s
}
return strings.ToUpper(s[:1]) + strings.ToLower(s[1:])
}
// 使用示例
func stringExample() {
text := "hello world 你好世界"
reversed := reverseString(text)
fmt.Printf("原文: %s\n", text)
fmt.Printf("反转: %s\n", reversed)
wordCount := countWords(text)
fmt.Printf("单词数: %d\n", wordCount)
capitalized := capitalizeFirst("go language")
fmt.Printf("首字母大写: %s\n", capitalized)
}
3. 数据验证函数
// 邮箱验证函数
func isValidEmail(email string) bool {
// 简单的邮箱格式验证
if len(email) < 5 {
return false
}
atIndex := strings.Index(email, "@")
dotIndex := strings.LastIndex(email, ".")
return atIndex > 0 && dotIndex > atIndex+1 && dotIndex < len(email)-1
}
// 密码强度验证
func validatePassword(password string) (bool, []string) {
var errors []string
isValid := true
if len(password) < 8 {
errors = append(errors, "密码长度至少8位")
isValid = false
}
hasUpper := false
hasLower := false
hasDigit := false
for _, char := range password {
switch {
case char >= 'A' && char <= 'Z':
hasUpper = true
case char >= 'a' && char <= 'z':
hasLower = true
case char >= '0' && char <= '9':
hasDigit = true
}
}
if !hasUpper {
errors = append(errors, "密码必须包含大写字母")
isValid = false
}
if !hasLower {
errors = append(errors, "密码必须包含小写字母")
isValid = false
}
if !hasDigit {
errors = append(errors, "密码必须包含数字")
isValid = false
}
return isValid, errors
}
// 使用示例
func validationExample() {
// 邮箱验证
emails := []string{"test@example.com", "invalid-email", "user@domain.org"}
for _, email := range emails {
if isValidEmail(email) {
fmt.Printf("✓ %s 是有效邮箱\n", email)
} else {
fmt.Printf("✗ %s 是无效邮箱\n", email)
}
}
// 密码验证
passwords := []string{"weakpass", "StrongPass123", "short"}
for _, pwd := range passwords {
valid, errors := validatePassword(pwd)
if valid {
fmt.Printf("✓ 密码 '%s' 强度合格\n", pwd)
} else {
fmt.Printf("✗ 密码 '%s' 不合格: %v\n", pwd, errors)
}
}
}
4. 工具函数
// 数组/切片工具函数
func findMax(numbers []int) (int, error) {
if len(numbers) == 0 {
return 0, errors.New("空切片没有最大值")
}
max := numbers[0]
for _, num := range numbers[1:] {
if num > max {
max = num
}
}
return max, nil
}
func contains(slice []string, item string) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}
func removeDuplicates(slice []int) []int {
seen := make(map[int]bool)
result := []int{}
for _, item := range slice {
if !seen[item] {
seen[item] = true
result = append(result, item)
}
}
return result
}
// 使用示例
func utilityExample() {
numbers := []int{3, 1, 4, 1, 5, 9, 2, 6, 5}
max, err := findMax(numbers)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("最大值: %d\n", max)
}
fruits := []string{"apple", "banana", "orange"}
fmt.Printf("是否包含 'banana': %v\n", contains(fruits, "banana"))
fmt.Printf("是否包含 'grape': %v\n", contains(fruits, "grape"))
unique := removeDuplicates(numbers)
fmt.Printf("原数组: %v\n", numbers)
fmt.Printf("去重后: %v\n", unique)
}
函数设计原则
1. 单一职责原则
// 好的设计 - 每个函数只做一件事
func calculateTax(income float64) float64 {
if income <= 5000 {
return 0
}
return income * 0.1
}
func formatCurrency(amount float64) string {
return fmt.Sprintf("¥%.2f", amount)
}
// 不好的设计 - 函数做了太多事情
func calculateAndFormatTax(income float64) string {
var tax float64
if income <= 5000 {
tax = 0
} else {
tax = income * 0.1
}
return fmt.Sprintf("¥%.2f", tax) // 混合了计算和格式化
}
2. 函数命名最佳实践
// 动词开头,清晰表达函数功能
func calculateAge(birthYear int) int { /* ... */ } // 计算年龄
func validateInput(data string) bool { /* ... */ } // 验证输入
func convertToUpper(text string) string { /* ... */ } // 转换为大写
// 布尔返回值使用 is/has/can 开头
func isEmpty(s string) bool { return len(s) == 0 }
func hasPermission(user User) bool { /* ... */ }
func canAccess(resource string) bool { /* ... */ }
// 获取数据使用 get/fetch 开头
func getUserById(id int) (User, error) { /* ... */ }
func fetchUserData(id int) ([]byte, error) { /* ... */ }
多返回值函数
// 返回多个值
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
// 使用示例
result, err := divide(10, 2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
命名返回值与非命名返回值
非命名返回值(普通返回值)
// 非命名返回值 - 必须在 return 语句中指定返回的值
func calculate(a, b int) (int, int, error) {
if b == 0 {
return 0, 0, fmt.Errorf("division by zero")
}
sum := a + b
quotient := a / b
return sum, quotient, nil // 必须显式返回所有值
}
// 使用示例
sum, quotient, err := calculate(10, 2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("Sum: %d, Quotient: %d\n", sum, quotient)
}
命名返回值
// 命名返回值 - 在函数签名中为返回值命名
func rectangle(length, width float64) (area, perimeter float64) {
area = length * width
perimeter = 2 * (length + width)
return // 空的 return 语句,自动返回命名的返回值
}
// 也可以显式返回,即使使用了命名返回值
func rectangleExplicit(length, width float64) (area, perimeter float64) {
area = length * width
perimeter = 2 * (length + width)
return area, perimeter // 显式返回
}
两种方式的对比
1. 语法差异
// 非命名返回值
func add(a, b int) int {
result := a + b
return result // 必须指定返回值
}
// 命名返回值
func addNamed(a, b int) (result int) {
result = a + b
return // 可以使用空 return
}
2. 复杂函数中的应用
// 非命名返回值 - 处理用户登录
func loginUser(username, password string) (string, bool, error) {
if username == "" {
return "", false, fmt.Errorf("username cannot be empty")
}
if password == "" {
return "", false, fmt.Errorf("password cannot be empty")
}
// 模拟验证逻辑
if username == "admin" && password == "123456" {
token := "jwt_token_example"
return token, true, nil
}
return "", false, fmt.Errorf("invalid credentials")
}
// 命名返回值 - 处理用户登录
func loginUserNamed(username, password string) (token string, success bool, err error) {
if username == "" {
err = fmt.Errorf("username cannot be empty")
return // 相当于 return "", false, err
}
if password == "" {
err = fmt.Errorf("password cannot be empty")
return
}
// 模拟验证逻辑
if username == "admin" && password == "123456" {
token = "jwt_token_example"
success = true
return // 相当于 return token, true, nil
}
err = fmt.Errorf("invalid credentials")
return // 相当于 return "", false, err
}
3. 在 defer 中修改返回值
// 命名返回值的特殊用法 - defer 可以修改返回值
func processFile(filename string) (result string, err error) {
defer func() {
if err != nil {
// 在 defer 中可以修改命名返回值
result = "处理失败"
err = fmt.Errorf("文件处理错误: %v", err)
}
}()
if filename == "" {
return "", fmt.Errorf("文件名不能为空")
}
// 模拟文件处理
result = "处理成功: " + filename
return
}
// 非命名返回值无法在 defer 中直接修改
func processFileRegular(filename string) (string, error) {
var result string
var err error
defer func() {
if err != nil {
// 这里修改 result 和 err 不会影响函数返回值
result = "处理失败" // 这个修改不会生效
}
}()
if filename == "" {
return "", fmt.Errorf("文件名不能为空")
}
result = "处理成功: " + filename
return result, nil
}
使用建议
何时使用命名返回值:
函数逻辑复杂,有多个出口点
需要在 defer 中修改返回值
返回值含义需要更清晰的文档说明
函数较长,命名有助于提高可读性
何时使用非命名返回值:
简单函数,逻辑清晰
返回值类型已经足够说明含义
不需要在 defer 中修改返回值
遵循团队代码风格约定
// 推荐:简单函数使用非命名返回值
func max(a, b int) int {
if a > b {
return a
}
return b
}
// 推荐:复杂函数使用命名返回值
func parseConfig(configPath string) (config *Config, warnings []string, err error) {
defer func() {
if err != nil {
config = nil // 确保错误时返回 nil
}
}()
// 复杂的配置解析逻辑...
return
}
2. 函数高级特性
可变参数函数
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
// 使用示例
fmt.Println(sum(1, 2, 3, 4, 5)) // 输出: 15
函数作为参数
func apply(fn func(int, int) int, a, b int) int {
return fn(a, b)
}
func multiply(x, y int) int {
return x * y
}
// 使用示例
result := apply(multiply, 3, 4) // 输出: 12
匿名函数和闭包
func main() {
// 匿名函数
square := func(x int) int {
return x * x
}
fmt.Println(square(5)) // 输出: 25
// 闭包示例
counter := func() func() int {
count := 0
return func() int {
count++
return count
}
}()
fmt.Println(counter()) // 输出: 1
fmt.Println(counter()) // 输出: 2
}
作者:admin 创建时间:2025-08-19 00:08
最后编辑:admin 更新时间:2025-09-21 19:50
最后编辑:admin 更新时间:2025-09-21 19:50