当前位置: 首页 > news >正文

Go语言-初学者日记(三):函数与方法

函数是 Go 程序的基础单元,方法是结构体的“超能力扩展包”。理解函数与方法的使用与内存行为,是写好 Go 程序的关键。


🧩 一、函数定义与调用

func sayHello(name string) string {
    return "Hello, " + name
}

msg := sayHello("Gopher")
fmt.Println(msg)
  • 使用 func 定义函数。
  • 每个参数与返回值都必须明确标明类型。
  • 支持类型合并,例如 (x, y int)

🧠 小贴士:

  • 函数名首字母大写 → 可导出(其他包可访问)。
  • 函数是 一等公民,可以赋值、传参、返回!

🔁 二、多返回值:Go 的“批发函数”

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("除数不能为0")
    }
    return a / b, nil
}

调用方式:

result, err := divide(10, 2)
if err != nil {
    fmt.Println("出错了:", err)
} else {
    fmt.Println("结果是:", result)
}

📌 多返回值特别适合“结果 + 错误”的组合,也是 Go 的错误处理核心风格。


📦 三、命名返回值 & 空白标识符 _

🏷 命名返回值
func getUser() (name string, age int) {
    name = "Alice"
    age = 18
    return // 自动返回 name 和 age
}

增加可读性,适合函数较长时使用。

🚮 空白标识符 _
_, err := divide(1, 0)
if err != nil {
    fmt.Println("捕捉到错误")
}
  • 用于忽略不想使用的值
  • 常用于函数返回多个值但只关心其中之一

🧱 四、变参函数:支持不定数量参数

func sum(nums ...int) int {
    total := 0
    for _, v := range nums {
        total += v
    }
    return total
}

调用方式:

fmt.Println(sum(1, 2, 3)) // 输出 6

也可以传入切片:

values := []int{1, 2, 3}
sum(values...) // 解包传参

🌀 五、函数也是值:匿名函数与闭包

匿名函数
greet := func(name string) {
    fmt.Println("Hi,", name)
}
greet("Gopher")
闭包:函数引用外部变量
func counter() func() int {
    i := 0
    return func() int {
        i++
        return i
    }
}

c := counter()
fmt.Println(c()) // 1
fmt.Println(c()) // 2

📌 闭包会“捕获并持有”其外层变量,即使函数返回后变量依然保留。


🏷️ 六、方法:结构体的专属技能

type User struct {
    Name string
}

func (u User) SayHi() {
    fmt.Println("Hi,我是", u.Name)
}
  • 方法语法类似函数,但多了接收者 (u User)
  • 用于给结构体添加行为(面向对象)

调用方式:

user := User{Name: "Gopher"}
user.SayHi()

☯️ 七、值接收者 vs 指针接收者

值接收者
func (u User) Rename(newName string) {
    u.Name = newName // 实际不影响外部 user 变量
}
指针接收者
func (u *User) Rename(newName string) {
    u.Name = newName // 可修改原结构体内容
}

调用时 Go 会自动推断:

user := User{Name: "Bob"}
user.Rename("Alice") // 自动转为 &user

🧠 使用建议:

需求推荐接收者类型
修改结构体字段指针接收者
不修改、结构体很小值接收者
实现接口(一般一致)统一指针或统一值接收者

💡 八、函数的内存行为与栈逃逸简析(进阶)

  • 函数参数和局部变量默认分配在栈上,函数调用结束即释放。
  • 若返回闭包或引用变量,变量可能逃逸到堆上。
func makePtr() *int {
    x := 10
    return &x // x 逃逸到堆上
}

使用 go build -gcflags="-m" 可查看逃逸分析信息:

go run -gcflags="-m" main.go

🧠 总结

特性是否支持示例说明
多返回值a, b := fn()
命名返回值return 自动返回
变参函数func f(...T)
匿名函数f := func() {...}
闭包捕获变量return func() { i++ }
方法绑定结构体func (t T) Method()
指针接收者修改func (t *T) Set()

🔨 推荐实战练习

  • ✅ 写一个计算器高阶函数 operate(a, b int, op func(int, int) int)
  • ✅ 实现 counter() 闭包,用于生成递增计数器
  • ✅ 编写 User 结构体,添加方法 Login()Logout()Rename()
  • ✅ 实现 sum(...int) 变参函数 + 使用切片解包测试

🪧 下一篇预告

👉 Go语言-初学者日记(四):包与模块管理,从“Hello World”走向项目实战!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/115180.html

相关文章:

  • C 语 言 --- 指 针 2
  • MyBatis小技巧与MyBatis参数处理
  • 【Firewalld】Linux中firewall-cmd的基本使用
  • Runnable组件容灾回退机制 with_fallback 深度解析降低程序错误率
  • 单链表的实现 | 附学生信息管理系统的实现
  • 3D打印技术助力高精密零件制造与维修工具革新
  • C# Winform 入门(13)之通过WebServer查询天气预报
  • 网络钓鱼攻击的威胁和执法部门的作用(第一部分)
  • 架构师面试(二十六):系统拆分
  • 【Csharp】获取实时的鼠标光标位置,测试用——做窗口软件绘图需要确定光标位置
  • GenerationMixin概述
  • Python Cookbook-5.5 根据内嵌的数字将字符串排序
  • 清明假期间
  • 数据分析-Excel-学习笔记
  • AI大模型:(二)2.1 从零训练自己的大模型概述
  • 【LeetCode 热题100】55:跳跃游戏(详细解析)(Go语言版)
  • 用python来操作mysql(复习一,主要是mysql连接和授权)
  • 【清明折柳】写在扬马三周目后
  • 【NLP 54、大模型训练相关知识】
  • Sentinel核心源码分析(上)
  • InfoSec Prep: OSCP靶场渗透
  • 定义和初始化 vector 对象(三十八)
  • TypeScript学习第十六篇 - interface和type的区别?
  • 【在线OJ项目测试报告】
  • 第十章Python语言高阶加强-SQL(数据库)
  • windows AndroidStudio上传maven中央仓库
  • MySQL约束详解:从入门到精通
  • java.util.Collections中常用api
  • Systemd安全加密备份系统与智能通知
  • 深信服Python开发面经及参考答案(110道题)